移动端图片适配的核心问题
核心痛点:
- 图片在不同屏幕宽度下(如 320px/375px/414px)拉伸 / 压缩变形;
- 高清屏(DPR=2/3)下图片模糊(1 张图适配所有 DPR 导致像素不足);
- 图片加载体积过大,影响移动端加载速度;
- 不同设备(手机 / 平板)图片显示比例失调。
解决方案
基础适配方案
css控制图片自适应,确保图片不超过容器宽度
/* 通用图片自适应样式 */
img {
/* 宽度自适应容器,高度自动按比例缩放 */
max-width: 100%;
height: auto;
/* 防止图片被挤压变形 */
object-fit: cover; /* 可选:cover(裁剪填充)/contain(完整显示)/fill(拉伸) */
/* 清除图片默认间隙(行内元素特性) */
display: block; /* 或 vertical-align: middle */
}
/* 针对固定比例的图片容器(比如16:9) */
.img-container {
position: relative;
width: 100%;
/* 16:9比例:高度=宽度*9/16=56.25% */
padding-top: 56.25%; /*实现固定比例容器:解决图片加载前容器高度塌陷的问题,提升页面体验*/
overflow: hidden;
}
.img-container img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
高清屏适配
1.根据设备像素比提供不同分辨率:使用### srcset 和 sizes 属性
srcset:定义图片集,1x/2x/3x对应 DPR,480w表示图片宽度为 480px;sizes:告诉浏览器图片在不同屏幕宽度下的显示宽度,浏览器会结合srcset选择最匹配的图片;- 优势:无需 JS,原生支持,性能最优。
<!-- 示例:为不同DPR提供2x/3x图,为不同宽度提供不同尺寸图 -->
<img
src="image_1x.jpg" <!-- 兜底图 -->
srcset="image_1x.jpg 1x, image_2x.jpg 2x, image_3x.jpg 3x" <!-- 按DPR选择 -->
alt="高清适配图"
>
<!-- 结合宽度的更精准适配 -->
<img
src="image_480.jpg"
srcset="image_480.jpg 480w, image_750.jpg 750w, image_1080.jpg 1080w" sizes="(max-width: 375px) 100vw, (max-width: 750px) 50vw, 300px"
alt="宽度适配图"
>
2.使用picture标签
- 特点:适合不同设备 / 场景需要不同格式 / 尺寸图片的情况(比如移动端显示竖图,平板显示横图)
<picture>
<!-- 高清屏(DPR>=2)显示2x图 -->
<source media="(-webkit-min-device-pixel-ratio: 2)" srcset="image_2x.jpg">
<!-- 超高清屏(DPR>=3)显示3x图 -->
<source media="(-webkit-min-device-pixel-ratio: 3)" srcset="image_3x.jpg">
<!-- 小屏幕(宽度<375px)显示小图 --> <source media="(max-width: 375px)" srcset="image_small.jpg">
<!-- 兜底图 -->
<img src="image_1x.jpg" alt="picture适配图">
</picture>
响应式图片加载
- WebP/AVIF 格式
- 同等画质下,WebP 比 JPG 小 30% 左右,AVIF 更小,优先使用:
<picture>
<source srcset="image.avif" type="image/avif">
<source srcset="image.webp" type="image/webp">
<img src="image.jpg" alt="高压缩比图片">
</picture>
2.懒加载:只加载视口内的图片,减少首屏加载压力
<!-- 原生懒加载(主流浏览器支持) -->
<img src="placeholder.jpg" data-src="image_1x.jpg" loading="lazy" alt="懒加载图">
<!-- 兼容方案(结合JS) -->
<script> // 简单懒加载实现 const lazyImages = document.querySelectorAll('img[data-src]'); const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; img.src = img.dataset.src; observer.unobserve(img); } }); }); lazyImages.forEach(img => observer.observe(img)); </script>