【性能优化】响应式图片
引言
在现代 Web 开发中,图片往往占据了页面总资源的 50% 以上。在移动设备和高分辨率屏幕普及的今天,如何让用户以最小的带宽成本获得最优的视觉体验,是性能优化中的关键课题。响应式图片正是解决这一问题的核心技术方案。
手段(从手段上通过格式优化与按需加载选图)
- 格式优化:优先使用现代高效格式(AVIF、WebP),不支持则降级到传统格式(JPG、PNG)
- 按需加载:根据图片显示尺寸(槽位分段适配)/视口宽度(视口分段适配)、设备像素比(DPR)选择最合适的图片资源
作用(从作用上减少带宽浪费、提升加载速度)
- 减少带宽浪费:避免在小屏设备上加载过大的图片,避免在低 DPR 设备上加载高清图片
- 提升加载速度:更小的图片体积意味着更快的首屏渲染和更流畅的用户体验
一、槽位适配(Slot-based Adaptation)
定义:以分段适配的方式,预先提供多档尺寸、多档 DPR 的候选图片,根据图片在页面中的实际显示宽度、**设备像素比(DPR)**选择最合适的一档资源。
技术实现:通过 HTML 的 <picture> + srcset + sizes 属性实现。
核心特性:
-
srcset定义了多个候选图片地址及宽度描述符(如image-400w.jpg 400w) -
sizes由多组「媒体条件 + 源尺寸值」组成,描述在不同视口下的槽位宽度(如(max-width: 600px) 100vw, 50vw) - 浏览器根据 媒体条件 与 源尺寸值 得出槽位宽度,再结合 设备像素比(DPR) 与 宽度描述符 选择最合适的图片
示例代码:
① 槽位分段 + 多格式(完整用法):
<picture>
<source
type="image/avif"
srcset="/images/hero-400w.avif 400w, /images/hero-800w.avif 800w, /images/hero-1200w.avif 1200w"
sizes="(max-width: 600px) 100vw, 50vw"
/>
<source
type="image/webp"
srcset="/images/hero-400w.webp 400w, /images/hero-800w.webp 800w, /images/hero-1200w.webp 1200w"
sizes="(max-width: 600px) 100vw, 50vw"
/>
<img
src="/images/hero-400w.jpg"
srcset="/images/hero-400w.jpg 400w, /images/hero-800w.jpg 800w, /images/hero-1200w.jpg 1200w"
sizes="(max-width: 600px) 100vw, 50vw"
alt="Hero Image"
/>
</picture>
② DPR + 格式适配(srcset 用 x 描述符,picture 做格式切换):
<picture>
<source type="image/avif" srcset="/images/hero.avif 1x, /images/hero@2x.avif 2x" />
<source type="image/webp" srcset="/images/hero.webp 1x, /images/hero@2x.webp 2x" />
<img
src="/images/hero.jpg"
srcset="/images/hero.jpg 1x, /images/hero@2x.jpg 2x"
alt="Hero Image"
/>
</picture>
二、视口适配(Viewport-based Adaptation)
定义:以分段适配的方式,结合格式选择(AVIF/WebP)、媒体查询(视口宽度、设备像素比 DPR)为每一档指定图片,浏览器根据当前视口、DPR 及格式支持情况匹配到对应的一档并加载该资源。
技术实现:
-
视口 × DPR 分段:通过 CSS 媒体查询
@media实现 -
格式选择(AVIF/WebP 等):依赖 JS 检测——在应用启动时探测浏览器支持情况,给
<html>添加.avif、.webp等 class,再由 CSS 选择器覆盖对应格式的背景图。CSS 的@supports对图片格式不可靠,故采用 JS + class 方案
示例代码(视口 × DPR 分段 + 格式覆盖):
① 格式检测并往 document 加 class(仅示例 AVIF):
// 用 1x1 AVIF data URI 探测,支持则在根节点加 .avif
const avifDataUri = 'data:image/avif;base64,AAAAIGZ0eXBhdmlm...'
const img = new Image()
img.onload = () => { if (img.width > 0) document.documentElement.classList.add('avif') }
img.onerror = () => {}
img.src = avifDataUri
② 视口 × DPR 分段 + 用 .avif 覆盖格式:
.hero {
// 降级格式(JPG):视口 × DPR
@media (width >= 0) {
@media (resolution >= 1dppx) {
background-image: url('/images/hero-400w.jpg');
}
}
@media (width >= 768px) {
@media (resolution >= 2dppx) {
background-image: url('/images/hero-800w@2x.jpg');
}
}
.avif & {
@media (width >= 0) {
@media (resolution >= 1dppx) {
background-image: url('/images/hero-400w.avif');
}
}
@media (width >= 768px) {
@media (resolution >= 2dppx) {
background-image: url('/images/hero-800w@2x.avif');
}
}
}
}
三、槽位适配与视口适配的对比
3.1 槽位适配更细腻精确
槽位适配在媒体查询的基础上,还依据图片在页面中的实际显示宽度选图,形成“二维精准匹配”。例如:视口 1920px 时,若图片只占 50vw(960px),通过 sizes="50vw" 浏览器会选约 1000w 的图,而视口适配只能按 1920px 选图,容易造成浪费。在复杂布局(多栏、网格等)中,这种差异更明显。
3.2 适用场景不同
槽位适配适用于页面中某些槽位的显示尺寸会随视口变化而变化的场景(如多栏、网格、响应式布局中宽度不固定的图片区域)。通过 sizes 声明各视口下的槽位宽度,浏览器按实际显示宽度选图,避免大视口下小槽位仍加载大图。
视口适配则适合整体随视口缩放的场景(如全屏头图、整页背景),只按视口宽度与 DPR 分段选图,不关心图片在页面中的实际占位大小。该方案在 H5 / 小程序 等移动端页面中应用广泛。
3.3 背景图
槽位适配依赖 HTML 的 sizes 来声明“图片在不同视口下的实际宽度”。CSS 的 background-image 没有等价语法,无法描述“背景在容器中的显示宽度”,只能通过媒体查询获知视口宽度与 DPR。因此背景图无法做槽位式选图,只能采用视口分段适配。