前端性能优化--图片
图片格式的选择
JPEG
有损压缩,高品质的压缩方式。图片体积压缩至原有体积的50%以下时,jpg仍然可以保持60%的品质。原理为以24位存储单个图,可以呈现多达1600万种颜色,足以满足大多数场景下对色彩的要求,这一点决定了它压缩前后的质量损耗并不容易被肉眼察觉。
优点:
网站呈现丰富的色彩。
有损压缩,通过压缩大大的减少图片的体积。一般图片用60%级别比较合适,大于75%的压缩等级,图片有明显的质量下降。
无兼容性问题。
缺点:
JPEG图像不支持透明度的处理,透明图片使用PNG。
处理矢量图形和logo等线条感较强、颜色对比强烈的图像时,人为压缩的图片模糊会相当明显。
使用场景:
- 适用于色彩丰富的图片,日常开发中,JPEG图片经常作为大的背景图、轮播图或banner图出现。
PNG
无损压缩,高保真的图片格式。同时支持8位和24位二进制的位数,八位的png最多指出256种颜色,24位可以呈现约1600万种。
优点:
网站呈现丰富的色彩,更强的色彩表现力,对线条的处理更加细腻。
支持透明度处理,透明图片的使用。
缺点:
- 体积太大
使用场景:
线条和对比度处理更具优势,我们主要用它来呈现小的logo、颜色简单且对比强烈的图片或对比等。
添加透明度,使用透明图片。
GIF
最多支持256种颜色的8位无损图片格式。
优点:
支持256种颜色,文件体积小。
支持透明。
支持动画。
缺点:
- 只支持简单色彩的图片。
使用场景:
展示无限循环的动画,比如图标、表情、广告位等。
简单色彩的图片使用。
webP
同时提供了有损压缩和无损压缩(可逆压缩)的图片文件格式。像JPEG一样对细接丰富的图片信手拈来,像PNG一样支持透明,像GIF一样可以显示动态图片。
优点:
色彩丰富。
支持透明。
支持动态图片。
无损压缩比PNG压缩减少了45%的文件大小。
缺点:
- 浏览器对webP支持并不普遍。ios系统基本不支持。
图片压缩
有损压缩
在压缩文件大小的过程中,损失了一部分图片的信息,也降低了图片的质量,并且这种损失是不可逆的。常见的压缩手段是按照一定的算法将邻近的像素点进行合并,去除了人肉眼无法识别的图片细节。jpg图片使用的就是有损压缩。
无损压缩
在压缩的过程中,图片的质量没有任何损伤。任何时候都可以从无损压缩过的图片中恢复出原来的信息。压缩算法是对图片的所有的数据进行编码压缩,能在保证图片的质量的同时降低图片的体积。例如png、gif使用的就是无损压缩。
类型 | 动画 | 压缩类型 | 浏览器支持 | 透明度 |
---|---|---|---|---|
GIF | 支持 | 无损 | 所有 | 支持 |
PNG | 不支持 | 无损 | 所以 | 支持 |
JPEG | 不支持 | 有损 | 所以 | 不支持 |
webP | 支持 | 无损或有损 | 部分支持 | 支持 |
压缩工具
webpack 压缩
webpack配置imge-webpack-loader进行图片压缩
1.安装依赖
npm install --save-dev image-webpack-loader
2.配置webpack
module.exports = {
...
module: {
rules: [
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[hash:7].[ext]'
},
},
{
loader: 'image-webpack-loader',
options: {
mozjpeg: {
progressive: true,
quality: 50,
},
optipng: {
enabled: true,
},
pngquant: {
quality: [0.5, 0.65],
speed: 4,
},
gifsicle: {
interlaced: false,
}
},
},
],
},
],
},
}
使用雪碧图
雪碧图,CSS Sprites,国内也叫 CSS 精灵,是一种 CSS 图像合成技术,主要用于小图片显示。
浏览器请求资源的时候,同源域名请求资源的时候有最大并发限制,chrome 为 6 个,就比如你的页面上有 10 个相同 CDN 域名小图片,那么需要发起 10 次请求去拉取,分两次并发。第一次并发请求回来后,发起第二次并发。如果你把 10 个小图片合并为一张大图片的画,那么只用一次请求即可拉取下来 10 个小图片的资源。减少服务器压力,减少并发,减少请求次数。
优点:
- 减少请求个数。
缺点:
- 生成图片体积大,减少请求个数同时增加了图片大小。
webpack合成雪碧图
有相应的插件提供了自动合成雪碧图的功能并且可以自动生成对应的样式文件webpack-spritesmith
var path = require('path')
var SpritesmithPlugin = require('webpack-spritesmith')
module.exports = {
// ...
plugins: [
new SpritesmithPlugin({
src: {
cwd: path.resolve(__dirname, 'src/ico'),
glob: '*.png',
},
target: {
image: path.resolve(__dirname, 'src/spritesmith-generated/sprite.png'),
css: path.resolve(__dirname, 'src/spritesmith-generated/sprite.styl'),
},
apiOptions: {
cssImageRef: '~sprite.png',
},
}),
],
}
将src/ico目录下的所有png文件合成雪碧图,并且输出到对应目录,同时还可以生成对应的样式文件,样式文件的语法会根据你配置的样式文件的后缀动态生成。
使用base64格式
将图片转换为base64编码字符串inline到页面或css中。
优点:
性能提升:减少http请求,base64可以随着HTML下载到本地。
加密:用户无法一眼看到图片的内容,只看到编码。
方便引用:全局公共文件内加类名。
缺点:
- 图片大,图片色彩层次比较丰富,不适合这种方式,base64编码后文件过大,增加HTML页面的大小,影响加载速度。
webpack配置url-loader
module.exports = {
...
module: {
rules: [
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10240,
name: utils.assetsPath('img/[name].[hash:7].[ext]'),
}
},
],
},
}
图片懒加载
图片懒加载的原理就是暂时不设置图片的 src 属性,而是将图片的 url 隐藏起来,比如先写在 data-src 里面,等当前图片是否到了可视区域再将图片真实的 url 放进 src 属性里面,从而实现图片的延迟加载。
优点:
减少资源的加载,页面启动只加载首屏的图片,这样能明显减少服务器的压力和流量,也能减小浏览器的负担。
防止并发加载的资源过多而阻塞js的加载,影响整个网站的启动,影响用户体验。
节省用户流量,有些用户并不想全部看完,全部加载会耗费大量流量。
js代码
function lazyload() {
let viewHeight = document.body.clientHeight //获取可视区高度
let imgs = document.querySelectorAll('img[data-src]')
imgs.forEach((item, index) => {
if (item.dataset.src === '') return
// 用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置
let rect = item.getBoundingClientRect()
if (rect.bottom >= 0 && rect.top < viewHeight) {
item.src = item.dataset.src
item.removeAttribute('data-src')
}
})
}
// 可以使用节流优化一下
window.addEventListener('scroll', lazyload)
IntersectionObserver计算位置
const imgs = document.querySelectorAll('img[data-src]')
const config = {
rootMargin: '0px',
threshold: 0,
}
let observer = new IntersectionObserver((entries, self) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
let img = entry.target
let src = img.dataset.src
if (src) {
img.src = src
img.removeAttribute('data-src')
}
// 解除观察
self.unobserve(entry.target)
}
})
}, config)
imgs.forEach((image) => {
observer.observe(image)
})
图片预加载
将图片提前加载到本地缓存中,从而提升用户体验。
1.css和JavaScript实现预加载
#preload-01 {
background: url(http://domain.tld/image-01.png) no-repeat -9999px -9999px;
}
#preload-02 {
background: url(http://domain.tld/image-02.png) no-repeat -9999px -9999px;
}
#preload-03 {
background: url(http://domain.tld/image-03.png) no-repeat -9999px -9999px;
}
function preloader() {
if (document.getElementById) {
document.getElementById('preload-01').style.background =
'url(http://domain.tld/image-01.png) no-repeat -9999px -9999px'
document.getElementById('preload-02').style.background =
'url(http://domain.tld/image-02.png) no-repeat -9999px -9999px'
document.getElementById('preload-03').style.background =
'url(http://domain.tld/image-03.png) no-repeat -9999px -9999px'
}
}
function addLoadEvent(func) {
var oldonload = window.onload
if (typeof window.onload != 'function') {
window.onload = func
} else {
window.onload = function () {
if (oldonload) {
oldonload()
}
func()
}
}
}
addLoadEvent(preloader)
2.使用JavaScript实现预加载
function preloader() {
if (document.images) {
var img1 = new Image()
var img2 = new Image()
var img3 = new Image()
img1.src = 'http://domain.tld/path/to/image-001.gif'
img2.src = 'http://domain.tld/path/to/image-002.gif'
img3.src = 'http://domain.tld/path/to/image-003.gif'
}
}
function addLoadEvent(func) {
var oldonload = window.onload
if (typeof window.onload != 'function') {
window.onload = func
} else {
window.onload = function () {
if (oldonload) {
oldonload()
}
func()
}
}
}
addLoadEvent(preloader)
渐进式图片
高品质图像加载完之前会先显示低画质版本。低画质版本由于画质低、压缩率高、尺寸小、加载很快。
普通图片渲染时,数据将按照存储时的顺序从上到下逐行扫描被显示出来的,直到所有的数据都被读取完毕,就完成了整张图片的显示。
渐进式图片渲染过程中,会先显示整个图片的模糊轮廓,随着扫描次数的增加,图片变得越来越清晰。这种格式的主要优点是在网络较慢的情况下,可以看到图片的轮廓知道正在加载的图片大概是什么。
注:
很多工具和库都支持导出渐进式JPEG,比如 ImageMagick, libjpeg, jpegtran, jpeg-recompress以及imagemin。 也可以使用 gulp-imagemin 进行批量转换。
Photoshop导出渐进式图片,保存为JPEG格式,勾选连续。