KAIROS.WORKSPACE
技术宇宙 / ONLINE
返回文章列表
前端工程beginner5 分钟

文章页图片的懒加载与淡入:不制造布局偏移的做法

正文图片用 loading=lazy + decode=async 延迟解码,配合占位尺寸与淡入,兼顾性能与体验,并处理失败与 reduced-motion。

#图片优化#性能#CLS#动效
排版
字号
行宽
目录 · 5 节

文章里一张大图,处理不好就是 LCP 杀手 + CLS 元凶。好消息是:绝大多数收益靠几行“该加的加上、该设的设对”就能拿到。

基线三件套

<img
  src="/img/diagram.png"
  alt="架构示意图"
  width="1200"
  height="800"
  loading="lazy"
  decoding="async"
/>
  • width/height(或 CSS aspect-ratio)是防 CLS 的第一功臣——浏览器据比例预留占位空间,图片加载完成不撑动版面。缺尺寸的图是内容站最常见的布局偏移来源。
  • loading="lazy":离视口远的图不请求。首屏 LCP 图千万别加——懒加载会延迟它自己的加载,把最大内容元素推后。判断标准:位于首屏折叠线以上的第一张图,用 loading="eager" 甚至 fetchpriority="high"
  • decoding="async":解码移出主线程,避免大图解码卡顿交互。

CSS 侧兜住尺寸

属性宽高会被样式覆盖,用 CSS 强制保持比例、限制不溢出容器:

.article-content img {
  max-width: 100%;
  height: auto;
  aspect-ratio: attr(width) / attr(height); /* 现代浏览器据属性自动推比例,这行作显式保险 */
}

实际现代浏览器已由 width/height 属性自动推 Aspect Ratio,CSS 这行更多是“确保不被某处 height: auto 之外的规则破坏”。

淡入:锦上添花但要处理边界

想给图片加“加载完成淡入”,务必处理三种“到不了 loaded”的情况,否则图会永久隐身:

function enhance(img) {
  if (matchMedia('(prefers-reduced-motion: reduce)').matches) return; // 直接可见
  if (img.complete && img.naturalWidth) return; // 已缓存:不淡入,直接显示
  img.dataset.reveal = 'pending';
  const reveal = () => {
    img.dataset.reveal = 'done';
    cleanup();
  };
  const fail = () => {
    img.dataset.reveal = 'done';
    cleanup();
  }; // 加载失败也要可见(别留隐藏态)
  const cleanup = () => {
    img.removeEventListener('load', reveal);
    img.removeEventListener('error', fail);
  };
  img.addEventListener('load', reveal);
  img.addEventListener('error', fail);
}
[data-reveal='pending'] {
  opacity: 0;
}
[data-reveal='done'] {
  opacity: 1;
  transition: opacity 400ms ease;
}

三个边界对应三条教训:

  1. reduced-motion 用户跳过淡入,直接可见;
  2. 命中缓存的图 complete=trueload 事件不会再触发——不判断就会卡在 pending 永久透明;
  3. 加载失败也必须解除隐藏——否则一张 404 图变成一块永远空白的隐形坑(比显示破图标更糟)。

客户端路由下还要在换页时移除这些 load/error 监听,避免泄漏。

响应式与格式

  • 需要真响应式尺寸时用 srcset/sizes,让浏览器按 DPR 与视口挑选;
  • 截图/图表类优先 WebP/AVIF(带 type<picture>srcset 回退);
  • 装饰性图 alt=""(不是省略 alt),信息性图 alt 描述内容而非文件名。

小结

图片优化的收益顺序很明确:设尺寸防 CLS > 别懒加载 LCP 图 > 异步解码 > 现代格式 > 淡入动效。前四条是纯工程正确,最后一条是体验糖——而糖必须把“缓存/失败/减弱动效”三个苦口处理掉,才不会变成新 bug。

Conversation

评论与互动

正在加载评论…

提交后需审核,不会立即公开。

Keep exploring

继续探索