Claude Code 图片懒加载实战:不拖慢 LCP 的安全做法
用 Claude Code 实现图片懒加载,覆盖 LCP、CLS、srcset、SEO 误区和验证。
图片懒加载不是把所有img都加上loading="lazy"。如果首屏 hero 图也被延迟,Largest Contentful Paint,也就是用户看到主要内容的时间,可能会变慢。如果商品列表、图库、相关文章缩略图全部提前加载,移动端又会浪费带宽。
这篇文章把适合初学者的安全做法整理成一套可交给 Claude Code 执行的规则:原生loading="lazy"、首屏 LCP 图片保持 eager、decoding、fetchpriority、防止 CLS 的尺寸、响应式srcset/sizes、高级场景的 IntersectionObserver、占位图、SEO/UX 坑、性能测量和安全提示词。技术判断参考了 MDN 的img元素、Intersection Observer API、web.dev 的浏览器级图片懒加载、Core Web Vitals和 Chrome 的LCP request discovery。
如果还要处理压缩、格式转换和 CDN,可以继续读图片优化、骨架屏加载和性能优化。
先记住规则
最重要的规则是:首屏可见的图片不要懒加载。只有滚动后才会看到的图片才适合懒加载。无论是否 lazy,都要用width和height,或者等价的aspect-ratio,提前保留空间,避免页面跳动。
| 图片位置 | loading | fetchpriority | decoding | 保护措施 |
|---|---|---|---|---|
| Hero 图或 LCP 候选 | eager或省略 | 可考虑high | sync或async | 必须能从初始 HTML 发现 |
| 文章中段图解 | lazy | auto | async | 保留尺寸 |
| 商品列表第二屏以后 | lazy | auto | async | 使用srcset和sizes |
| 轮播、无限滚动 | 视情况 | auto | async | 必要时用 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。
- 重构时删掉
width和height。 - 所有图片都被加上
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 提示词里提前写明失败例和验证任务。
免费 PDF: Claude Code 速查表
输入邮箱即可获取一页 PDF,整理常用命令、审查习惯和安全工作流。
我们会妥善保护你的信息,不发送垃圾邮件。
把 Claude Code 变成真正能带来结果的工作流
先领取中文说明的免费 PDF,再进入英文商品页选择合适的教材。如果你需要团队落地、流程设计或内容变现支持,也可以直接咨询。
关于作者
Masa
专注 Claude Code 实务流程、团队导入和内容转化的工程师。
相关文章
Claude Code权限安全阶梯:逐步放开访问而不失控
从只读到有限编辑、验证命令和部署检查的 Claude Code 权限升级流程。
Claude Code 小PR证据包:让小改动真正可审查
用差异、验证命令、公开URL、CTA路径和回滚说明,把Claude Code的小PR变得可审查。
Claude Code 提交前 Review Gate:同时检查差异、测试、公开 URL 和 CTA
提交前用 Claude Code 审查差异范围、build、公开 URL、Gumroad 链接、咨询 CTA、缺少测试和无关文件。