图像是 Web 重要组成部分,将图像优化好了性能问题就解决了至少一半
要在 Web 网页上放置图像,我们需要使用 <img>
元素。这是一个空元素,它需要指定一个 src
属性。如果图像名为 avatar.jpg 并且它与您的 HTML 文档位于同一路径中,则可以按如下方式引入:
<img alt="avatar" src="avatar.jpg">
为了确保图像的可访问性,我们添加了
alt
属性。该属性的值应该是图片的文字描述,当图像无法显示或看不到时,作为图像的替代;例如,用户通过屏幕阅读器访问您的页面。
接下来,我们添加 width
和 height
属性来指定图像的宽度和高度,也就是图像的尺寸。
<img alt="avatar" height="400" src="avatar.jpg" width="400">
在图像上指定 width
和 height
属性,浏览器就知道要为这张图像保留多少空间。如果忘记指定图像的尺寸会导致布局偏移,因为浏览器不确定图像需要多少空间,布局偏移就会影响性能
但是作为一个响应式设计的网页我们图像的父级元素的大小可能不足以容纳一个固定大小的图像,
因此我们需要一个样式来使图像的大小不会超出父级元素
img {
max-width: 100%;
}
这时又会引出另一个问题,图像的宽度变得自适应了,而高度被我们添加的 height
属性固定了,为了使图像高度也能自适应,我们需要通过样式给图像的高度指定为自动:
img {
max-width: 100%;
height: auto;
}
到这里我们的图像可以完美地适应父级元素的大小了,
不过我们这里又可以发现另外一个问题,无论图像的容器有多大加载的始终都是同一张图像,很显然,在一个小空间里加载显示一张高分辨率的图像是一种浪费,我们希望能够为不同大小的图像容器提供不同分辨率的图像
响应式图像
如果我们可以给一个图像容器提供多张图像让浏览器自行选择合适的那一张来加载显示岂不是很美好?
<img>
元素新增了一个 srcset
属性,这是一个集合属性,通过该属性我们可以给图像提供多个源路径,使用逗号进行分隔
<!-- 提供单个图像源 -->
<img src="avatar-800w.jpg">
<!-- 提供多个图像源 -->
<img src="avatar.jpg"
srcset="avatar-small.jpg 400w,
avatar-large.jpg 800w">
同时,每个图像路径后面可以添加一个宽度描述符,用空格分割,比如 400w
表示 avatar-small.jpg 图像的宽度是 400 像素
宽度描述符的作用是告诉浏览器这张图像的宽度,让浏览器在还没有下载图像的情况下就能确认图像的宽度,注意宽度描述符的单位是
w
和 srcset
属性一起出现在标准中的还有一个 sizes
属性,这两个属性需要搭配使用才能让浏览器知道自己该加载哪张图像
<img src="avatar.jpg"
srcset="avatar-small.jpg 400w,
avatar-large.jpg 800w"
sizes="400px">
sizes
属性用于告诉浏览器该图像可能的显示宽度,比如这里的值 400px
表示该图像可能的显示宽度为 400 像素,所以浏览器会加载 400 像素宽的小图像,而忽略那张 800 像素宽的大图像,毕竟图像分辨率越大理论上来讲文件体积也就越大
sizes
的值必须是一些固定有效的长度,比如 100vw, 100px 等等,不能是百分比之类的,sizes
的作用只是告诉浏览器该图像可能的显示宽度
另外 sizes
属性还支持使用媒体查询提供由逗号分隔的多个宽度值,为不同视口大小指定不同的图像可能宽度
<img src="avatar.jpg"
srcset="avatar-small.jpg 400w,
avatar-large.jpg 800w"
sizes="(max-width: 600px) 400px, 800px">
sizes="(max-width: 600px) 400px, 800px"
表示视口宽度不足 600 像素的时候,图像宽度为 400 像素,此时浏览器依然是加载小的图像,而当视口宽度大于 600 像素的时候,图像宽度为 800 像素,浏览器就会加载大的图像
响应式图像除了可以适应视口的宽度,还可以适应不同的设备像素比,比如这里,当视口宽度不足 600 像素的时候,如果设备像素比为 1 则浏览器还是加载显示小的那张图像,但是如果设备像素比为 2 的话,则浏览器会加载显示大图像
总之,浏览器可以结合这几个条件从 srcset
中提供的图像中选择最合适的那张
如果浏览器不支持 srcset
和 sizes
属性,将会忽略它们,并使用 src
提供的图像,目前主流浏览器都支持这两个属性,详见 https://caniuse.com/srcset
传统图像格式
JPEG 是使用广泛的格式,这是一种有损格式,解码速度快,适用于照片,但是它不支持透明,所以,我们同时会使用另一种图像格式
PNG 支持透明,不过它是一种无损格式,压缩率不高,如果用于照片的话图像文件的体积往往会很大
通常情况下这两种格式我们会根据实际情况选择使用,色彩丰富的照片就考虑使用 JPEG 格式,需要透明的时候就用 PNG 格式,这两种图像格式都不支持动画
GIF 支持动...,我们现在应该没有理由还使用 GIF
这些传统图像格式各自都有明显的缺点,为了解决这些缺点,有了接下来这些新的图像格式
现代图像格式
WebP 图像格式由 Google 创建,同时支持无损和有损压缩以及透明,动画,绝大多数情况下是比 JPEG, PNG 和 GIF 更优秀的图像格式,是设计出来取代他们的,创造至今已经得到了绝大多数浏览器支持(https://caniuse.com/webp)
AVIF 支持无损和有损压缩,动画,透明,是比 WebP, JPEG, PNG 和 GIF 更优秀的图像格式,是设计出来取代他们的,目前被部分主流浏览器的新版本支持(https://caniuse.com/avif),Safari 暂时不支持,但预计不久就会,毕竟 Apple 公司是创建这种格式的组织成员之一,现在我们也可以在项目中使用了,后面会有使用方式
虽然 AVIF 比 WebP 更优秀,但是 WebP 比 AVIF 支持的浏览器更多,所以目前来说这两种格式我们都会使用到,现代图像格式的引用方式和传统图像是一样一样的,通过 <img>
元素
<img src="avatar.avif">
不过对于不支持这种格式的浏览器来说就显得无语了,好在有个新的 <picture>
元素来应对这种情况
使用 <picture>
元素可以为单个图像提供多种图像格式供浏览器选择。一个 <picture>
元素必需包含一个 <img>
元素,
<picture>
<img alt="avatar" src="avatar.jpg">
</picture>
只是这样还没有任何特别的作用,我们还可以在 picture 元素中使用 <source>
元素为图像提供不同格式的源
<picture>
<source srcset="avatar.avif" type="image/avif">
<img alt="avatar" src="avatar.jpg">
</picture>
这样就比较有意思了,如果浏览器支持 AVIF 格式的图像就会加载显示 avatar.avif 文件,同时忽略该 picture
元素内其它格式,否则就会降级加载 avatar.jpg 文件
如果浏览器连 <picture>
元素都不支持,将会简单地忽略它,直接显示 <img>
元素的内容,另外还可以提供多个 <source>
元素,浏览器会自上而下地选择第一个它支持的格式
<picture>
<source srcset="avatar.avif" type="image/avif">
<source srcset="avatar.webp" type="image/webp">
<img alt="avatar" src="avatar.jpg">
</picture>
将需要优先显示的放在最前面就可以了,type
属性用于告诉浏览器该图像的格式,所有主流浏览器都支持 <picture>
元素 ,关于 <picture>
元素的浏览器支持可查看 https://caniuse.com/picture
响应式现代图像格式
我们注意到 <source>
元素指定资源路径的属性是 srcset
,也就是说,一个 <source>
元素也是可以同时指定多个图像路径的,结合前面的内容整合到一起,一个图像元素可能就会如下所示
<picture>
<source
sizes="(max-width: 600px) 100vw, 50vw"
srcset="avatar-small.avif 400w,
avatar-large.avif 800w" type="image/avif">
<source
sizes="(max-width: 600px) 100vw, 50vw"
srcset="avatar-small.webp 400w,
avatar-large.webp 800w" type="image/webp">
<img sizes="(max-width: 600px) 100vw, 50vw" src="avatar.jpg"
srcset="avatar-small.jpg 400w,
avatar-large.jpg 800w">
</picture>
图像压缩
图像压缩可以分为无损和有损两种,无损压缩就是在不损失图像质量的情况下减小图像文件的大小,如果无损压缩已经不能给我们带来多少收益的时候,我们可以考虑有损压缩,适当降低一下图像的质量,可以有效地减小图像文件的大小
我们将图像转换为 WebP 或者 AVIF 的时候,应该从源文件直接导出或者通过无损的格式(如 PNG)来转换,如果用有损的格式(如 JPEG)再来转换为有损的 AVIF 的话,那图像质量就损失两次了
延迟加载
只需要给 <img>
元素添加一个 loading="lazy"
属性即可
<img loading="lazy" src="avatar.jpg">
搭配 <picture>
元素一起食用,
<picture>
<source srcset="avator.avif" type="image/avif">
<img loading="lazy" src="avator.jpg">
</picture>
不支持的浏览器会自动忽略该属性,可以给不支持的浏览器提供插件来实现该功能
<img alt="avator" class="lazyload" data-src="avator.jpg" loading="lazy">
<script>
;(function() {
if ('loading' in HTMLImageElement.prototype) {
var images = document.querySelectorAll('img.lazyload')
images.forEach(function(img) {
img.src = img.dataset.src
})
} else {
var script = document.createElement('script')
script.async = true
script.src = '//afarkas.github.io/lazysizes/lazysizes.min.js'
document.body.appendChild(script)
}
})()
</script>
图像解码
浏览器从下载好图像到显示出来,中间还有一个解码的过程,我们可以通过一个属性将这个过程设定为异步的
<img decoding="async" src="avatar-800w.jpg">
就这样
响应式背景图像
根据设备像素比提供不同的背景图像,需要使用到 image-set
表示法,该方法可以提供多个图像路径,并给每个路径指定一个设备像素比
.selector {
background-image: image-set(
url(./photo-small.jpg) 1x,
url(./photo-large.jpg) 2x);
}
指定设备像素比用 1x
, 2x
这种方式,浏览器会根据设备像素比加载对应的图像,还可以为不支持浏览器提供后备内容
.selector {
background-image: url(./photo-small.jpg);
background-image: image-set(
url(./photo-small.jpg) 1x,
url(./photo-large.jpg) 2x);
}
所以主流浏览器的最新版本都支持,参考 https://caniuse.com/css-image-set,大部分浏览器需要添加 -webkit-
前缀,更完整的写法为
.selector {
background-image: url(./photo-small.jpg);
background-image: -webkit-image-set(
url(./photo-small.jpg) 1x,
url(./photo-large.jpg) 2x);
background-image: image-set(
url(./photo-small.jpg) 1x,
url(./photo-large.jpg) 2x);
}
不过浏览器厂商前缀更科学的方式是通过工具来添加,如 Autoprefixer
现代图像格式
使用现代格式的背景图像,还是使用 image-set
表示法,并指定一个图像格式,同时提供后备选项
.selector {
background-image: url(./photo.jpg);
background-image: image-set(
url(./photo.avif) type("image/avif"),
url(./photo.jpg) type("image/jpeg"));
}
同样在 image-set
中,需要优先考虑的图像放在前面,目前支持 type
描述的浏览器并不多,能支持 type
描述的同样也已经支持 AVIF 格式的图像了,所以上面的写法其实有点多余
不过因为可以为不支持的浏览器提供后备内容,所以可以放心使用
工具
- WebP 在线转换 WebP Converter
- AVIF 在线转换 AVIF Converter
- AVIF 在线转换 AVIF Converter
- Squoosh 是一个 Web 应用程序,支持多种图像格式
- sharp
- libvips