图片为什么拖慢页面
网页体积里图片通常占大头,一张没优化的大图可能比整页代码还重。图片拖慢页面不只是下载慢,还会挤占带宽、阻塞渲染、让移动端流量吃紧。优化的思路有三层:让图片体积更小、让浏览器只加载需要的大小、让不在视口的图晚点加载。
- 格式WebP 与 AVIF 比 JPEG 更小。
- 尺寸srcset 按屏幕密度选图。
- 懒加载视口外的图延后加载。
- 占位加载过程不闪空白。
格式选型:WebP 与 AVIF
同样画质下,WebP 比 JPEG 小约三成,AVIF 更小但兼容性差一些。选型看目标用户:现代浏览器占多数就大胆用 WebP,AVIF 作为增强;老浏览器回退 JPEG。实现上用 picture 元素按支持度切换格式,浏览器自己挑能播的。
<picture>
<source srcset="img.avif" type="image/avif">
<source srcset="img.webp" type="image/webp">
<img src="img.jpg" alt="描述文字">
</picture>
图片本身的压缩也要做:调好质量参数、去掉多余元数据、必要时用工具压缩,别只换格式不压缩。
响应式尺寸与 srcset
手机屏和电脑屏需要的图片尺寸不同,一张 2000 像素宽的大图在手机上纯属浪费。srcset 加 sizes 让浏览器按视口宽度和屏幕密度选择合适尺寸,同时设置 width 和 height 属性,预留图片占位,防止布局跳动。
<img
srcset="img-480.jpg 480w, img-960.jpg 960w, img-1920.jpg 1920w"
sizes="(max-width: 768px) 100vw, 960px"
src="img-960.jpg" alt="描述文字"
width="960" height="540">
宽度属性带上后,浏览器能在图片下载前按比例预留空间,页面滚动和布局都稳定。
懒加载:loading 与 IntersectionObserver
首屏以下的图片可以延迟到接近视口再加载。原生 loading=lazy 一行属性就能用,复杂场景用 IntersectionObserver 自己控制加载时机,比如图片进入视口前一定距离就开始加载。
<img src="img.jpg" loading="lazy" alt="描述文字">
const observer = new IntersectionObserver(function(entries){
entries.forEach(function(entry){
if (entry.isIntersecting) {
loadImage(entry.target);
observer.unobserve(entry.target);
}
});
}, { rootMargin: "200px" });
懒加载注意:首屏关键图不要懒加载,否则白屏更久;用原生 loading 为主,自定义方案做补充。
占位与渐进加载
图片加载期间的空白会让页面显得卡。常见做法有几种:纯色占位、模糊小图占位、宽高比占位。轻量方案是给容器设好宽高比,背景用与图片主色调接近的纯色,图片到位后淡入,视觉连贯不跳。
.img-wrap { aspect-ratio: 16 / 9; background: #dbe4f0; }
.img-wrap img { opacity: 0; transition: opacity .3s; }
.img-wrap img.loaded { opacity: 1; }
加动画要克制,图片本身才是重点;占位样式只做过渡,别加花哨装饰。
缓存与 CDN 配合
图片是静态资源,缓存收益极高。给图片设长缓存,文件名带内容指纹,改图就换文件名,缓存自然失效;再配合 CDN 就近分发,首屏加载速度会明显提升。CDN 通常还提供压缩与格式转换,把 WebP 自动下发。
Cache-Control: public, max-age=31536000, immutable
图片数量大时要规划目录与命名规范,方便 CDN 预热与统计分析;热图走 CDN 加速,冷图给短缓存,避免缓存堆积。
落地清单
- 图片先压缩,再按场景换 WebP 或 AVIF。
- 用 srcset 加 sizes 按屏选尺寸。
- width 与 height 属性写上,防布局跳动。
- 首屏图不懒加载,视口外才 lazy。
- 加载期用纯色或模糊占位,到位后淡入。
- 文件名带指纹设长缓存,配合 CDN 分发。