005.LCP 触发条件与原理
什么是 LCP
LCP 测量的是视口内最大的图像或文本块的渲染时间,是 Core Web Vitals 三大核心指标之一。良好的 LCP 应该在 2.5 秒以内
LCP 候选元素类型
| 元素类型 | 说明 |
|---|---|
<img> |
包括动画 GIF/PNG(使用首帧呈现时间) |
<svg> 内的 <image> |
SVG 内嵌图像 |
<video> |
使用海报图像或首帧时间(取较早者) |
CSS background-image |
通过 url() 加载的背景图 |
| 文本块 | 包含文本节点的块级元素 |
排除的元素:
opacity: 0的不可见元素- 覆盖整个视口的元素(如背景)
- 低信息熵的占位图片
元素大小计算规则
可见大小 = 视口内可见部分的面积
| 场景 | 计算方式 |
|---|---|
| 图片 | min(可见大小, 原始大小) |
| 文本 | 能包含所有文本节点的最小矩形 |
| 超出视口 | 只计算视口内的部分 |
| CSS 装饰 | margin/padding/border 不计入 |
触发时机与更新规则
页面加载 → 首次绘制 → 持续监听 → 用户交互 → 停止
↓ ↓ ↓
初始LCP 更新LCP 最终LCP
关键触发点:
- 首次绘制时:浏览器派发初始 LCP 条目
- 发现更大元素时:派发新的 LCP 条目替换旧值
- 资源加载完成时:图片/字体加载前不算作已渲染,加载后重新计算
- 元素移除时:已移除的元素仍保持候选资格,除非发现更大元素
停止报告的条件
用户交互会终止 LCP 观察:
| 交互类型 | 说明 |
|---|---|
| keydown | 键盘按键 |
| click | 鼠标点击 |
| scroll | 页面滚动 |
| tap | 触摸屏轻触 |
⚠️ 注意:web-vitals 库中没有监听 scroll,因为滚动可以被程序触发,不够可靠
页面状态变化也会触发最终报告:
visibilitychange→hiddenpagehide事件
API 关键属性
const observer = new PerformanceObserver((list) => {
const entries = list.getEntries();
const lastEntry = entries[entries.length - 1];
console.log({
element: lastEntry.element, // LCP 元素
size: lastEntry.size, // 元素大小
startTime: lastEntry.startTime, // 推荐使用此值作为 LCP
renderTime: lastEntry.renderTime,// 渲染时间(跨域可能为 0)
loadTime: lastEntry.loadTime, // 加载时间
url: lastEntry.url // 图片 URL
});
});
observer.observe({ type: "largest-contentful-paint", buffered: true });
小提示
startTime = renderTime || loadTime,建议使用 startTime 因为 renderTime 对跨域资源可能不可用
完整生命周期图
导航开始
│
├─► 首个内容绘制 (FCP)
│
├─► LCP 候选 #1 (小文本块)
│
├─► LCP 候选 #2 (更大的图片) ← 替换 #1
│
├─► 图片加载完成 → 重新计算大小
│
├─► LCP 候选 #3 (Hero Image) ← 替换 #2
│
└─► 用户点击/滚动 → 停止观察,#3 成为最终 LCP