Web 中图片的使用
一图胜千言,图片是网页不可或缺的一部分。
在 Web 中,正确地使用图片能提高加载性能、节约带宽。本文介绍图片的相关概念、常见格式,以及如何正确引用图片。
图片的一些概念
彩色深度
彩色深度标准通常有以下几种:
- 8 位色:每个像素所能显示的彩色数为 2 的 8 次方,即 256 种颜色。
- 16 位增强色:16 位彩色,每个像素所能显示的彩色数为 2 的 16 次方,即 65536 种颜色。
- 24 位真彩色:每个像素所能显示的彩色数为 24 位,即 2 的 24 次方,16777216(约 1677 万) 种颜色。
- 32 位真彩色:即在 24 位真彩色图像的基础上再增加一个表示图像透明度信息的 Alpha 通道。32 位真彩色并非是 2 的 32 次方的色数,它其实也是 16777216(约 1677 万) 多色,不过它增加了 256 阶颜色的透明度,为了方便称呼,就规定它为 32 位色。
光栅图和矢量图
对于图片,一般分光栅图(点阵图)和矢量图:
- 光栅图:基于像素(pixel)构成的图像。JPEG、PNG、WebP 等都属于此类。
- 矢量图:使用点、线和多边形等几何形状来构图,与分辨率无关,可任意缩放且不失真。SVG 就是一种矢量图。
无压缩、无损压缩和有损压缩
- 无压缩:即不对图片数据进行压缩处理,能准确地呈现原图片。BMP 格式就是其中之一。
- 无损压缩:即压缩算法对图片的所有的数据进行编码压缩,能在保证图片的质量的同时降低图片的尺寸。PNG 是其中的代表。
- 有损压缩:即压缩算法不会对图片所有的数据进行编码压缩,而是在压缩的时候,去除了人眼无法识别的图片细节。因此有损压缩可以在同等图片质量的情况下大幅降低图片的尺寸。其中的代表是 JPG。
常用图片格式
ICO(1985)
ICO 是 Windows 的图标文件格式,一个文件可以存储单个图案,也可以包含多尺寸、多色板的多个图标。
ICO(Microsoft Windows 图标)由微软为 Windows 桌面图标设计。早期 Internet Explorer 约定:在网站根目录放置名为 favicon.ico 的文件,作为收藏夹、标签页等位置的站点图标。
ICO 文件以目录开头,列出每个图标的详细信息,目录之后是图标数据。每个图标可以是没有文件头的 BMP 图像,也可以是完整的 PNG 图像(含文件头)。若仍使用 ICO,内嵌图优先用 BMP:直到 Windows Vista 才支持 ICO 内的 PNG,旧系统兼容性不好。
GIF(1987)
GIF 是一种无损的、索引色模式的点阵图,所以 GIF 每帧图所表现的颜色最多为 256 种。GIF 能够支持动画,也能支持背景透明,这点连古老的 IE 6 都支持,所以在以前想要在项目中使用背景透明图片,其中一种方案就是生成 GIF 图片。
其特点:
- 体积小:优秀的压缩算法使其在一定程度上保证图像质量。
- 动画:可插入多帧,从而实现动画效果。
- 透明:可设置透明色以产生对象浮现于背景之上的效果。
- 色彩失真:由于采用了 8 位压缩,最多只能处理 256 种颜色,故不宜应用于真彩色图片。
备注:在兼容性允许的情况下,动图效果可改用静音(muted)的 video 代替 GIF。相同效果下,GIF 大约比视频(MPEG-4)大 5~20 倍。
Base64(编码,不是图片格式)
Base64 不是一种图片格式,而是把二进制数据编成文本的方法(常见规范见 RFC 2045,1996)。把图片编成字符串后写进 HTML、CSS,图片随页面一起下载,不再单独发一次 HTTP 请求去拉图。
其特点:
- 无额外请求;
- 没有跨域问题,无需考虑缓存、文件头或 Cookie;
- 体积比原文件大约大 1/3,且编码、解码有额外消耗。适合很小的图标,不适合大图。
PNG(1996)
PNG 使用无损压缩,压缩效率通常优于未压缩位图,支持比 GIF 更高的颜色深度,以及完整的 Alpha 透明度。
PNG 得到广泛支持,所有主要浏览器都对其功能提供全面支持。Internet Explorer 在 4~5 中引入了 PNG 支持,直到 IE 9 才比较完整,此前(尤其是 IE 6)透明度和 Gamma 等问题很多。
PNG 格式有三种常见色深用法:
- PNG-8:是无损的、索引色模式的点阵图,跟 GIF 类似,而且也支持背景透明。相比 GIF,透明时边缘噪点更少、颜色更好,体积也往往更小。尽量用 PNG-8 而不是 GIF,除非需要动画。
- PNG-24:是无损的、使用直接色的点阵图。它能接近 JPEG 的色彩表现,但算法是无损的,体积通常比 JPEG、GIF、PNG-8 大得多,比 BMP 小。
- PNG-32:就是在 PNG-24 的基础上,增加了 8 位透明度通道。
其特点:
- 体积小:无损压缩,支持 256 色调色板技术。
- 真彩色:最高支持 48 位真彩色图像以及 16 位灰度图像。
- 透明:支持 Alpha 通道的透明、半透明特性。
- 可预览:渐进显示和流式读写,适合在网络传输中先看到预览再展示全貌。
- 其他:支持图像亮度的 Gamma 校准信息、支持存储附加文本信息(图像名称、作者、版权、创作时间、注释)、使用 CRC 防止文件出错。标准 PNG 一个文件一幅图;动画要用 APNG(见下文),不要和 PNG 本身混为一谈。
JPEG(1992)、JPEG 2000(1997-2000)
JPEG 是目前最广泛使用的静止图像有损压缩标准;常见的 .jpg、.jpeg 文件多采用 JFIF、Exif 等封装。二者扩展名没有实质区别,只是不同系统上的习惯写法不同。
JPG、JPEG 采用直接色的点阵图,能比较好地表现各种色彩,压缩时会有失真,也因此体积更轻量。
JPEG 2000(约 1997-2000)是另一套压缩标准,浏览器几乎不支持,Web 上很少使用。
其特点:
- 适用于储存 24 位全彩影像
- 采取的压缩方式通常为有损压缩
- 不支持透明或动画
- 压缩比越高影像耗损越大,失真越严重
- 压缩比约 10:1 时,肉眼往往难以分辨压缩图与原图的差别
SVG(1999)
SVG 是无损的矢量图(放大时,不会失真),是一种基于 XML 的矢量图形格式,它将图像的内容指定为一组绘制命令,这些命令可以创建形状、线条、应用颜色、过滤器等。SVG 文件是图表、图标和其他可以精确绘制成任意大小的图像的理想选择。因此,SVG 在现代 Web 设计中的用户界面元素中很受欢迎。
SVG 文件是包含源代码的文本文件,在解释时,它会绘制所需的图像。
其特点:
- 可伸缩性
- 体积小。图标、简单图形的 SVG 通常比同等的 GIF、JPEG、PNG 小得多,在极高分辨率下也是如此;复杂照片不适合做成 SVG
- 支持动画
- 与 DOM 无缝衔接。可以直接使用 HTML、CSS 和 JavaScript(例如动画)来操作
- 复杂度高会减慢渲染速度,不适合游戏类等高互动动画
APNG(2004)
APNG 是 Mozilla 首次引入的一种文件格式,它扩展了 PNG 标准以添加对动画图像的支持。在概念上类似于已经使用了几十年的动画 GIF 格式,APNG 更强大的是它支持各种颜色深度,而动画 GIF 仅支持 8 位索引颜色。
WebP(2010)
WebP 通过基于 VP8 视频编解码器的预测编码支持有损压缩,以及使用替换重复数据的无损压缩。有损 WebP 图像比视觉上相似压缩级别的 JPEG 图像平均小 25%~35%。无损 WebP 图像通常比 PNG 格式的相同图像小 26%。
WebP 还支持动画:在有损 WebP 文件中,图像数据由 VP8 比特流表示,其中可能包含多个帧。无损 WebP 拥有描述动画的 ANIM 块和表示动画序列帧的 ANMF 块。支持循环播放。
WebP 在主流浏览器的现行版本中已得到广泛支持。从 Can I Use - webp 看,现代浏览器基本全覆盖;不支持的主要是 IE,以及很旧的 Safari(Safari 14 起已支持)。
其特点:
- 同时提供有损压缩和无损压缩两种模式。
- 文件体积小:在有损与无损压缩上,表现都会优于传统 JPEG、PNG。WebP 无损压缩比 PNG 的体积小 26%,有损压缩比同质量的 JPEG 体积小 25%~34%。同时 WebP 也支持透明度,一张无损 WebP 若要带透明度,大约只需多 22% 的文件大小。
- 支持动画。
- 旧浏览器:IE 11 及以下不支持;Safari 14 之前不支持或部分支持。
BMP
BMP(位图图像)文件类型在 Windows 计算机上最为普遍,通常仅用于 Web 应用程序和内容中的特殊情况。
BMP 是无损的、既支持索引色也支持直接色的点阵图。这种图片格式几乎没有对数据进行压缩,通常体积比较大。
TIFF
TIFF 是一种光栅图形文件格式,用于存储扫描的照片,也可以存其他类型的图像。它偏「重」:文件往往比其他格式大。原因是通常包含元数据,以及多数 TIFF 要么未压缩,要么压缩后仍然很大。
TIFF 支持多种压缩方法,但最常用的是传真软件使用的 CCITT Group 4(以及对于较旧的传真系统,Group 3)压缩系统,以及 LZW 和有损 JPEG 压缩。
注意:很久以前,一些浏览器在网页内容中支持 TIFF 图像;现在需要使用特殊库或浏览器插件才能解析。因此 TIFF 不宜直接嵌在网页里,但在需要精确编辑或打印时,仍常提供可下载的 TIFF 文件。
响应式图片
响应式图片是能在不同屏幕尺寸、分辨率的设备上良好显示的图片。
响应式图片主要包含:
- 不同的屏幕尺寸和分辨率的设备上,使用不同的图片以适应不同的空间分配(美术设计)。
- 不同的屏幕尺寸和分辨率的设备上,引用相同显示效果的图片但包含多个不同的分辨率(分辨率切换)——没有必要在比图片实际尺寸小的屏幕上显示一张大图,这样做会浪费带宽。
srcset、sizes 属性
标准的 img 元素传统上仅仅允许给浏览器指定唯一的资源文件。
<img src="elva-fairy-800w.jpg" alt="Elva dressed as a fairy">
但可以使用两个新的属性 srcset、sizes,来提供更多额外的资源图像和提示,帮助浏览器选择正确的一个资源。
srcset 属性定义了允许浏览器选择的图像集,以及每个图像的大小。其值是以逗号分隔的一个或多个字符串列表,每一个字符串由以下组成:
- 一个指向图像的 URL
- 一个空格
- 一个描述符:
- 宽度描述符(正整数 +
w):该整数是图像的真实大小(物理像素)。 - 像素密度描述符(正浮点数 +
x),默认值为1x。
- 宽度描述符(正整数 +
注意:一个 srcset 属性中混合使用宽度描述符和像素密度描述符,会导致该值无效;重复的描述符(比如,两个源相同,且描述符也相同)也是无效的。
注意:若 srcset 使用宽度描述符(w),建议同时写 sizes。未写时默认按 100vw(整个视口宽度)来选图,容易下到过大的图,但 srcset 不会因此被忽略。
sizes 属性描述图像的预期显示宽度,定义了一组媒体条件,并指明当某些媒体条件为真时,什么样的图片尺寸是最佳选择。其值是以逗号隔开的一个或多个字符串:
- 一个媒体条件(最后必须有一项,用作默认)
- 一个空格
- 一个资源尺寸的值,表示被用来指定图像的预期尺寸(逻辑像素、CSS 像素)。
<img
srcset="
01s2fcqhjeddyx0wjvb1kt3439.jpg 320w,
01fnn86u44kv9nhsigucvw3737.png 800w,
01df276351fc64000e76100056bf2b.jpg 1200w,
01k5lfhmvy0ghhmj3azqsk3439.png 1440w"
sizes="
(max-width: 320px) 320px,
(max-width: 800px) 800px,
(max-width: 1200px) 1200px,
(max-width: 1400px) 1440px,
1200px"
src="01k5lfhmvy0ghhmj3azqsk3439.png"
alt="响应式图片"
>
当 srcset 中的资源使用密度像素描述符(x)时,用户代理会根据设备像素比来选择显示的图像;当使用宽度描述符(w)时,先检查 sizes 列表中哪个媒体条件是第一个为真,再查看该媒体查询对应的资源尺寸的值,然后计算图像实际渲染的物理像素(与设备像素比有关),最后加载最接近该物理像素值的图像。
注意:图像物理像素值和屏幕密度密切相关,DP(物理像素)= DIP(逻辑像素) × DPR(设备像素比)。如,(max-width: 320px) 320px,在 1 倍屏下,表示渲染图像的实际宽度是 320px * 1 = 320px;在 2 倍屏下,表示渲染图像的实际宽度是 320px * 2 = 640px。
注意:sizes 只对宽度描述符(w)起作用。如果 srcset 里用的是密度像素描述符(x),sizes 不起作用。另外,如果没有设置 srcset,或者该属性没有值,那么 sizes 也不起作用。
注意:支持 srcset 的浏览器会按 srcset、sizes 选图;src 作为不支持 srcset 时的回退。使用 x 描述符时,src 还会被当作 1x 候选。
picture 元素
picture 元素通过包含零或多个 source 元素和一个 img 元素,为不同的显示、设备场景提供图像版本。浏览器会选择最匹配的子 source 元素,如果没有匹配的,就选择 img 元素的 src 属性中的 URL。然后,所选图像呈现在 img 元素占据的空间中。
picture 的常见使用场景:
- 艺术指导——针对不同
media条件裁剪或修改图像; - 根据浏览器是否支持特定格式,提供不同的图像格式。
要决定加载哪个 URL,用户代理检查每个 source 的 srcset、media 和 type 属性,来选择最匹配页面当前布局、显示设备特征等的兼容图像。
picture 常用属性:
media属性:提供一个媒体条件(类似于媒体查询)。如果该媒体条件匹配结果为 false,那么这个source元素会被跳过。type属性:为资源指定一个 MIME 类型。如果用户代理不支持指定的类型,那么这个source元素会被跳过。srcset属性:以逗号分隔的一个或多个字符串列表表明一系列用户代理使用的可能的图像。
<picture>
<source media="(max-width: 320px)" srcset="01s2fcqhjeddyx0wjvb1kt3439.jpg">
<source media="(max-width: 640px)" srcset="01fnn86u44kv9nhsigucvw3737.png">
<source media="(max-width: 800px)" srcset="01df276351fc64000e76100056bf2b.jpg">
<source media="(max-width: 1200px)" srcset="01k5lfhmvy0ghhmj3azqsk3439.png">
<img style="width: 100%;" src="01s2fcqhjeddyx0wjvb1kt3439.jpg" alt="必须要有一个 img 元素">
</picture>
还有一种解决方案
图片链接中携带图片处理参数(宽、高等等),由资源存储服务端处理图片文件。比如:阿里云 - 新版图片处理指南,当然,前提是你的资源存储在阿里云。
<img src="https://image-demo.oss-cn-hangzhou.aliyuncs.com/example.jpg">
<img src="https://image-demo.oss-cn-hangzhou.aliyuncs.com/example.jpg?x-oss-process=image/resize,h_50,m_lfit">
正确使用图片
使用什么格式的图片
- 内容图片:比较重要,且一般颜色较为丰富、文件体积较大,优先考虑:WebP > JPEG > PNG(PNG-8 色位太低,而 PNG-24 压缩率低,文件体积大)。 兼容性允许时,也可用 AVIF(通常比 WebP 更小),用
<picture>做格式回退。 - 背景图:次重内容,起修饰作用,优先考虑:WebP > PNG-8、JPEG > GIF。
使用多大的图片
使用规则:图片都应该经过压缩处理,压缩后的图片不应该出现肉眼可感知的失真区域,图片大小控制在 200KB 以内。
注意:质量约 60 的 JPEG 与质量更高的相比,肉眼已看不出明显区别,因此保存 JPEG 时质量一般控制在 60。保真度要求高的图片可适量提高到 80。
常见问题
如何判断浏览器是否支持 WebP?
WebP 是 Google 推出的一种支持有损压缩和无损压缩的图片文件格式。WebP 无损压缩比 PNG 的体积小 26%,有损压缩比同质量的 JPEG 体积小 25%~34%。同时 WebP 也支持透明度,一张无损 WebP 若要带透明度,大约只需多 22% 的文件大小。
现行主流浏览器均已支持 WebP;IE 11 及以下不支持,Safari 14 之前不支持或部分支持。
判断浏览器是否支持 WebP,有以下几种方法:
通过 canvas 来判断(常用)
创建一个 canvas 元素,然后把它转成 image/webp 格式的 Data URL。如果 Data URL 里面包含 webp,则代表当前浏览器支持 WebP 格式,反之则不支持。
function isSupportWebp () {
try {
return document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') === 0
} catch (err) {
return false
}
}
通过加载 WebP 图片判断(官方推荐)
通过 WebP 的一些特征来加载一张 WebP 图片,如果能获取到图片的宽度和高度,就说明是支持 WebP 的,反之则不支持。
function checkWebpFeature(feature, callback) {
const kTestImages = {
lossy: "UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA",
lossless: "UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==",
alpha: "UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==",
animation: "UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA"
}
const img = new Image()
img.onload = function () {
const isSupported = (img.width > 0) && (img.height > 0)
callback(feature, isSupported)
};
img.onerror = function () {
callback(feature, false)
}
img.src = "data:image/webp;base64," + kTestImages[feature]
}
checkWebpFeature('lossy', function (feature, isSupported) {
console.log(isSupported)
});
服务端根据请求 Header 信息判断(不推荐,依赖服务端)
在图片请求发出的时候,Request Headers 里有 Accept,服务端可以根据 Accept 里面是否有 image/webp 进行判断。
...
accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8
...
如何让网页快速变灰(包括图片)
简单来讲,网页变灰只需要在所有元素前面加了一个滤镜即可,几行简单的代码就可以。
html {
-webkit-filter: grayscale(100%);
-moz-filter: grayscale(100%);
-ms-filter: grayscale(100%);
-o-filter: grayscale(100%);
filter: grayscale(100%);
filter: progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);
}
什么情况下图片会、不会加载?
img设置了src(或已选中srcset)后就会发起加载,即使设了display: none。loading="lazy"会推迟到接近视口时再加载。已经加载过的相同图片不会重复加载。
设置
display: none的元素,其background-image属性的图片不会加载。设置
visibility: hidden的元素,其background-image属性、后代img元素、后代元素的background-image属性的图片都会加载,并且会渲染。样式定义了
background-image,但没有用在元素上,图片不会加载。:hover伪类下的background-image,在触发时加载。JS 创建
Image对象并设置src时,图片会加载。const img = new Image() img.src = "./pic1.png"