Tips & Tricks (更新: 2026/6/2)

Claude Code 图片懒加载实战:不拖慢 LCP 的安全做法

用 Claude Code 实现图片懒加载,覆盖 LCP、CLS、srcset、SEO 误区和验证。

Claude Code 图片懒加载实战:不拖慢 LCP 的安全做法

图片懒加载不是把所有img都加上loading="lazy"。如果首屏 hero 图也被延迟,Largest Contentful Paint,也就是用户看到主要内容的时间,可能会变慢。如果商品列表、图库、相关文章缩略图全部提前加载,移动端又会浪费带宽。

这篇文章把适合初学者的安全做法整理成一套可交给 Claude Code 执行的规则:原生loading="lazy"、首屏 LCP 图片保持 eager、decodingfetchpriority、防止 CLS 的尺寸、响应式srcset/sizes、高级场景的 IntersectionObserver、占位图、SEO/UX 坑、性能测量和安全提示词。技术判断参考了 MDN 的img元素Intersection Observer API、web.dev 的浏览器级图片懒加载Core Web Vitals和 Chrome 的LCP request discovery

如果还要处理压缩、格式转换和 CDN,可以继续读图片优化骨架屏加载性能优化

先记住规则

最重要的规则是:首屏可见的图片不要懒加载。只有滚动后才会看到的图片才适合懒加载。无论是否 lazy,都要用widthheight,或者等价的aspect-ratio,提前保留空间,避免页面跳动。

图片位置loadingfetchprioritydecoding保护措施
Hero 图或 LCP 候选eager或省略可考虑highsyncasync必须能从初始 HTML 发现
文章中段图解lazyautoasync保留尺寸
商品列表第二屏以后lazyautoasync使用srcsetsizes
轮播、无限滚动视情况autoasync必要时用 IntersectionObserver

常见错误是认为“图片大,所以必须 lazy”。正确问题应该是:这张图片是否影响用户第一眼看到的内容?Chrome 的 LCP 指南明确提醒,LCP 图片应该尽早被浏览器发现并获得合适优先级,不要随手加loading=lazy

可直接复制的 HTML

下面的第一张图是首屏 hero 图,所以使用 eager 和高优先级。第二张图在正文下方或商品列表后半段,使用原生 lazy 和异步解码。

<img
  class="hero-image"
  src="/images/hero/product-dashboard-1200.webp"
  srcset="
    /images/hero/product-dashboard-640.webp 640w,
    /images/hero/product-dashboard-1200.webp 1200w
  "
  sizes="100vw"
  alt="产品仪表盘的首屏画面"
  width="1200"
  height="675"
  loading="eager"
  fetchpriority="high"
  decoding="sync"
/>

<img
  class="article-image"
  src="/images/articles/setup-step-800.webp"
  srcset="
    /images/articles/setup-step-400.webp 400w,
    /images/articles/setup-step-800.webp 800w
  "
  sizes="(max-width: 720px) 100vw, 720px"
  alt="设置步骤截图"
  width="800"
  height="450"
  loading="lazy"
  decoding="async"
/>

decoding="async"只是浏览器提示,不是万能加速按钮。正文图片、缩略图、相关推荐通常适合它。Hero 图可以用sync,也可以保持async后实测。重点是不要凭感觉选择属性,而是看 LCP 和布局稳定性。

用 CSS 防止 CLS

CLS 是 Cumulative Layout Shift,意思是页面加载过程中元素移动的程度。图片没有预留高度时,正文、广告、订阅表单和购买按钮会被向下挤。读者本来要点 CTA,却因为图片突然出现点错位置,这就是实际的 UX 问题。

.image-frame {
  aspect-ratio: 16 / 9;
  background: #f3f4f6;
  overflow: hidden;
}

.image-frame > img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

@media (prefers-reduced-motion: no-preference) {
  .image-frame > img {
    transition: opacity 180ms ease-out;
  }
}

如果 CMS 能拿到原图宽高,就把它们保存下来并传给模板。外部图片尺寸未知时,至少给容器设置稳定的aspect-ratio,再让真实图片用object-fit适配。这样不如真实尺寸精确,但比零高度占位安全得多。

React 组件化

让 Claude Code 修改 React 项目时,最好把规则封装到一个小组件中。这样优先图片 eager,普通正文图片 lazy,所有图片都保留尺寸,不容易在批量替换时漏掉。

type SmartImageProps = {
  src: string;
  srcSet?: string;
  sizes?: string;
  alt: string;
  width: number;
  height: number;
  priority?: boolean;
  className?: string;
};

export function SmartImage({
  src,
  srcSet,
  sizes,
  alt,
  width,
  height,
  priority = false,
  className,
}: SmartImageProps) {
  const loading = priority ? "eager" : "lazy";
  const fetchPriority = priority ? "high" : "auto";
  const decoding = priority ? "sync" : "async";

  return (
    <span
      className={`image-frame ${className ?? ""}`}
      style={{ aspectRatio: `${width} / ${height}` }}
    >
      <img
        src={src}
        srcSet={srcSet}
        sizes={sizes}
        alt={alt}
        width={width}
        height={height}
        loading={loading}
        fetchPriority={fetchPriority}
        decoding={decoding}
      />
    </span>
  );
}

这个组件故意保持简单。它不把重要图片藏进 JavaScript,也不强行发明新的图片管线。Next.js、Astro 或 CMS 组件都可以套用同样的策略。

三个真实产品场景

第一个场景是电商商品网格。第一屏的几个商品可能马上可见,不能全部 lazy。第二屏以后的商品、推荐商品、评论图片、浏览历史才更适合 lazy。失败例是给每个缩略图都加fetchpriority="high",浏览器会把所有请求都当成紧急任务,反而拖慢 CSS、字体或真正的 hero 图。

第二个场景是媒体文章和教程。封面图通常是 LCP 候选,要 eager。正文里的步骤截图、代码块后的图解、相关文章卡片可以 lazy。失败例是用模糊背景做占位,却把真实图片alt留空。只要图有信息价值,搜索引擎和屏幕阅读器就需要真实说明。

第三个场景是 SaaS 仪表盘。头像、客户 logo、报表缩略图和审计截图可能成批出现,离屏行 lazy 有帮助。但顶部主图表、引导说明、影响转化的 CTA 附近不要随便延迟。要评估 CTA 和收入事件,可以结合Analytics 实现一起设计。

第四个场景是图库或横向轮播。现在原生 lazy 很多时候已经够用,但如果图片在自定义滚动容器中、轮播 slide 被隐藏、或者你要控制提前 300px 加载,就可以使用 IntersectionObserver。

什么时候用 IntersectionObserver

先选原生 lazy。只有在需要更细控制时再使用 IntersectionObserver,例如进入视口前 300px 加载、替换data-src、移除占位 class,或监听某个滚动容器。

<img
  class="js-lazy-image"
  src="/images/placeholders/report-thumb.svg"
  data-src="/images/reports/report-2026.webp"
  data-srcset="/images/reports/report-2026.webp 1x"
  alt="月度报表缩略图"
  width="640"
  height="360"
/>
const lazyImages = document.querySelectorAll("img[data-src]");

function loadImage(img) {
  img.src = img.dataset.src;

  if (img.dataset.srcset) {
    img.srcset = img.dataset.srcset;
  }

  img.removeAttribute("data-src");
  img.removeAttribute("data-srcset");
}

if ("IntersectionObserver" in window) {
  const observer = new IntersectionObserver((entries, currentObserver) => {
    entries.forEach((entry) => {
      if (!entry.isIntersecting) return;

      loadImage(entry.target);
      currentObserver.unobserve(entry.target);
    });
  }, {
    rootMargin: "300px 0px",
    threshold: 0.01,
  });

  lazyImages.forEach((image) => observer.observe(image));
} else {
  lazyImages.forEach(loadImage);
}

即使走 JavaScript 路径,也要保留宽高。data-src图片在 JavaScript 失败时可能永远不会加载,所以不要把主要产品图、文章封面图或 SEO 关键图放在这种模式里。

测量与验证

Core Web Vitals 关注 LCP、INP 和 CLS。常见良好阈值是 LCP 不超过 2.5 秒、INP 不超过 200 毫秒、CLS 不超过 0.1。图片懒加载主要影响 LCP 和 CLS。

npm install web-vitals
import { onCLS, onINP, onLCP } from "web-vitals";

onLCP((metric) => {
  const lastEntry = metric.entries.at(-1);
  console.log("LCP", metric.value, lastEntry?.element);
});

onCLS((metric) => {
  console.log("CLS", metric.value, metric.entries);
});

onINP((metric) => {
  console.log("INP", metric.value, metric.entries);
});

在 Chrome DevTools 的 Performance 面板中,确认 LCP 元素是不是预期的 hero 图,图片请求是否能从 HTML 很早发现,是否有图片造成布局移动。上线后再看 PageSpeed Insights、Search Console 和自己的分析数据。实验室分数有用,但真实移动网络会暴露不同瓶颈。

给 Claude Code 的安全提示词

Claude Code 很擅长批量替换,所以必须先写范围、禁止事项和验证。

{
  "goal": "安全地为图片增加懒加载",
  "scope": [
    "只处理文章正文和商品列表图片",
    "不要懒加载首屏图片或 LCP 候选图片"
  ],
  "rules": [
    "每个 img 都要保留 alt、width、height",
    "折叠线以下图片使用 loading=\"lazy\" 和 decoding=\"async\"",
    "hero 图使用 loading=\"eager\" 或省略 loading",
    "fetchpriority=\"high\" 最多用于 1 张 LCP 候选图"
  ],
  "verification": [
    "检查 MDX 和代码围栏",
    "用 DevTools 检查 LCP 和 CLS",
    "在移动端宽度检查图片、文字和 CTA 是否重叠"
  ]
}

还要让 Claude Code 汇报哪些图片没有 lazy,以及原因。最好的懒加载实现通常包含有意保留的非改动。

失败例清单

  • Hero 图、主商品图或顶部 CTA 背景被 lazy。
  • 重构时删掉widthheight
  • 所有图片都被加上fetchpriority="high"
  • srcset候选图比例不一致,却没有 art direction。
  • 以为 CSS 背景图也能使用loading属性。
  • 有意义的图解被设置为空alt
  • 重要图片完全依赖 JavaScript 注入src
  • 占位图比真实内容更抢眼。

CTA 与实测记录

图片懒加载不是为了分数好看。它会影响读者是否继续阅读、CTA 是否稳定可点、商品列表是否顺滑、SaaS 用户能否快速开始操作。个人实践可以从免费 Claude Code cheatsheet开始;需要可复用提示词和审查模板时看产品页;团队要同时处理性能、SEO、分析和转化路径时,可以使用Claude Code 培训与咨询

这次刷新中,我按上面的官方文档重新核对了判断,并把文章改成“先决定哪些图片不能 lazy,再处理其余图片”的流程。Masa 实测时最稳定的组合是:hero eager、正文下方截图 lazy、所有图片都有尺寸、移动端用srcset分流,并在 Claude Code 提示词里提前写明失败例和验证任务。

#Claude Code #图片懒加载 #Lazy Loading #Core Web Vitals #React
免费

免费 PDF: Claude Code 速查表

输入邮箱即可获取一页 PDF,整理常用命令、审查习惯和安全工作流。

我们会妥善保护你的信息,不发送垃圾邮件。

把 Claude Code 变成真正能带来结果的工作流

先领取中文说明的免费 PDF,再进入英文商品页选择合适的教材。如果你需要团队落地、流程设计或内容变现支持,也可以直接咨询。

Masa

关于作者

Masa

专注 Claude Code 实务流程、团队导入和内容转化的工程师。