简单的图片处理汇总。
- 图片比较
- JPEG / JPG
- PNG8 / PNG24
- SVG
- 雪碧图(CSS Sprites)
- Base64
- WebP
- 图片压缩 & 转换
- 优雅降级
图片比较
JPEG / JPG
特点是有损压缩,体积小,不支持透明。适用于呈现色彩丰富的图片,常作为大的背景图,轮播图,banner图。
JPG以24位存储图,可以呈现多达1600万种颜色,足以应对绝大多数场景下对色彩的要求。
最大的特点是有损压缩。压缩算法非常高效,即使是“有损”压缩,仍然是一种高质量的压缩方式。当图片体积被压缩到50%以下时,JPG仍然可以保持住60%的品质。有损压缩在如轮播图上确实很难露出马脚,但处理矢量图形,logo等线条感强,颜色对比强烈的图像时,压缩导致的图片模糊会相当明显。
另外,JPEG不支持透明度处理,透明图片需要用PNG。
PNG8 / PNG24
特点是无损压缩,体积大,支持透明。适用于小logo,颜色简单对比强烈的图片或背景(复杂的,色彩层次丰富的图片一般会用JPG)。
8和24都是二进制位数,8位最多支持256种颜色,24位可以呈现1600万种颜色。
PNG是无损压缩的高保真图片格式,有比JPG更强的色彩表现力,对线条的处理更加细腻,对透明度有良好的支持。弥补了JPG的局限性。
唯一的缺点是体积大。
SVG
特点是支持独立文本文件,体积小,不失真,兼容性好。
SVG(可缩放矢量图形)是一种基于XML语法的图像格式,对图像的处理不是基于像素点,而是基于对图像的形状描述,和其他图片种类有本质的区别。
可以写代码一样定义SVG,将它写在HTML里,成为DOM的一部分。也可以写入.svg后缀的独立文件中(.svg的使用方式和其他普通图片无异)。.svg文件可以被其他工具读取和修改,具有较强的灵活性。
相比PNG和JPG,SVG的体积更小,可压缩性更强。最显著的优点是:作为矢量图,可以无限放大而不失真。所以SVG在视网膜显示屏上,也可以展现出很好的成像品质。一张SVG足以适配n种分辨率。
缺点是渲染成本比较高,对性能来说不利。而且存在学习成本(因为它是可编程的)。
雪碧图(CSS Sprites)
将各种小图标和小背景合并到一张图片上,用CSS定位来显示其中的每一部分,可以减少加载网页图片的HTTP请求数,从而提升网页性能。
Base64
是一种基于8bit字节码的编码方式,可以直接将编码结果写入HTML或CSS中。
可以理解为雪碧图的补充,同样可以减少图片的HTTP请求数。适用于一些更新频率非常低的小图片。
缺点是编码后的体积通常会比图片的原始体积大1/3,如果将大图进行base64,体积增大的更加明显,即使减少了HTTP请求,但文件体积的增加可能导致得不偿失。
WebP
旨在加快图片的加载速度,像JPEG一样对细节丰富的图片信手捏来,像PNG一样支持透明,像GIF一样可以显示动图,集各种图片格式的优点于一身。
缺点是新推出,存在浏览器兼容性问题,需要考虑优雅降级。还会增加服务器的负担,和编码JPG文件相比,编码同样质量的WebP文件会占用更多的计算资源。
Android和iOS的app只要引入Google提供的解码库,都可以很轻松的支持WebP格式。不过在web上,WebP的支持还不是很广泛,具体可查Can I Use。
图片压缩 & 转换
大多图片云服务都支持上传的图片转成webp格式(如果不支持,放弃它^_^),或者你在本地用imagemin将图片转成webp格式,无脑上传到静态服务器上也行。
imagemin提供了很多插件,例如:
格式 | 有损 | 无损 |
---|---|---|
JPEG | imagemin-mozjpeg | imagemin-jpegtran |
PNG | imagemin-pngquant | imagemin-optipng |
GIF | imagemin-giflossy | imagemin-gifsicle |
SVG | imagemin-svgo | – |
WebP | imagemin-webp | – |
用例参照官网也很简单,按官网示例将功能实现,是我们底层码农的尊严:
const fse = require('fs-extra'); const path = require('path'); const imagemin = require('imagemin'); const imageminMozjpeg = require('imagemin-mozjpeg'); const imageminPngquant = require('imagemin-pngquant'); const imageminWebp = require('imagemin-webp'); const srcDir = path.resolve(__dirname, '../tmp/images'); const distDir = path.resolve(__dirname, '../tmp/build/images'); (async() => { await imagemin([`${srcDir}/*.{jpg,png}`], distDir, { plugins: [ imageminMozjpeg({ quality: 70 }), imageminPngquant({ quality: [0.6, 0.8] }) ] }); await imagemin([`${distDir}/*.{jpg,png}`], distDir, { use: [ imageminWebp({ quality: 50 }) // imageminWebp({lossless: true}) // 无损压缩 ] }); })();
优雅降级
HTML端可以使用<picture>标签,指定多种格式的图片,保证优雅降级。
<picture class="picture"> <source type="image/webp" srcset="image.webp"> <img class="image" src="image.jpg"> </picture>
除了上面<picture>标签指定多种格式的图片外,很多懒加载的页面常见的做法是:将图片的URL放在img元素的一个自定义data属性中,如data-src,然后在适当的时机,例如页面滑动到可视区域内,将URL放入src属性。
同理,我们可以根据浏览器是否支持WebP格式,给img元素赋予不同的src值:
function checkWebp(callback) { var img = new Image(); img.onload = function () { var result = (img.width > 0) && (img.height > 0); //通过图片宽度值判断图片是否可以显示 callback(result); }; img.onerror = function () { callback(false); }; img.src = 'data:image/webp;base64,UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA'; } function showImage(useWebp){ var imgs = Array.from(document.querySelectorAll('img')); imgs.forEach(function(i){ var src = i.attributes['data-src'].value; if (useWebp){ src = src.replace(/\.jpg$/, '.webp'); } i.src = src; }); } checkWebp(showImage);
不想像上面这样全部img都替换的话,可以将判断是否支持webp的结果,存入localStorage,每次要替换时,从localStorage中读取浏览器是否支持,不用每次都检查一遍。
其他方式,如引入js版webp的解码器,将所有的webp图片用JS解码后转换为base64,然后替换掉原来的URL,但考虑到JS解码较慢,暂不推荐。