Core Web Vitals
Core Web Vitals(核心网页指标)是 Google 定义的一组衡量用户体验的关键性能指标。这些指标直接影响 Google 搜索排名,包括 LCP(最大内容绘制)、INP(交互到下一帧绘制)和 CLS(累积布局偏移)。本节将详细介绍每个指标的定义、优化策略和 Lighthouse 评分方法。
前置知识
阅读本节前,建议先了解:减少 DOM 节点数
Core Web Vitals 概览
| 指标 | 全称 | 衡量内容 | 良好阈值 |
|---|---|---|---|
| LCP | Largest Contentful Paint | 加载性能 | <= 2.5 秒 |
| INP | Interaction to Next Paint | 交互性能 | <= 200 毫秒 |
| CLS | Cumulative Layout Shift | 视觉稳定性 | <= 0.1 |
LCP(最大内容绘制)
定义
LCP 测量页面主要内容元素变为可见的时间。通常是最大的图片、文本块或视频元素。
HTML 中的 LCP 元素
html
<!-- 可能的 LCP 元素 -->
<h1>大标题文本</h1> <!-- 文本块 -->
<img src="hero-banner.jpg" alt="横幅"> <!-- 图片 -->
<video src="intro.mp4" poster="video.jpg"> <!-- 视频 -->
<div style="background: url(bg.jpg)">...</div> <!-- 背景图片 -->LCP 优化策略
| 策略 | 说明 |
|---|---|
| 优化服务器响应时间 | TTFB < 800ms |
| 内联关键 CSS | 减少渲染阻塞 |
| 优化图片 | WebP/AVIF、压缩、预加载 |
| 使用 CDN | 全球加速 |
| 预加载 LCP 元素 | <link rel="preload"> |
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LCP 优化示例</title>
<!-- 内联关键 CSS -->
<style>
body { margin: 0; font-family: sans-serif; }
.hero { height: 50vh; position: relative; }
.hero img { width: 100%; height: 100%; object-fit: cover; }
</style>
<!-- 预加载 LCP 图片 -->
<link rel="preload" href="/images/hero.webp" as="image" fetchpriority="high">
</head>
<body>
<div class="hero">
<img
src="/images/hero.webp"
alt="首屏横幅"
fetchpriority="high"
width="1200"
height="600"
/>
</div>
</body>
</html>INP(交互到下一帧绘制)
定义
INP 测量用户交互到页面视觉响应的时间。它取代了 FID(First Input Delay),更全面地衡量页面交互性能。
INP 优化策略
| 策略 | 说明 |
|---|---|
| 减少主线程工作 | 拆分长任务 |
| 使用 Web Worker | 将计算移到后台 |
| 避免长任务 | 使用 requestIdleCallback |
| 优化事件处理 | 防抖、节流 |
| 减少 DOM 大小 | 减少查询和布局时间 |
javascript
// 使用 requestIdleCallback 延迟非关键工作
function handleUserClick(event) {
// 立即处理关键任务(UI 更新)
updateUI();
// 延迟非关键任务
requestIdleCallback(() => {
logAnalytics(event);
sendToServer(event);
});
}
// 长任务拆分
function processLargeData(data) {
const CHUNK_SIZE = 100;
let index = 0;
function processChunk() {
const chunk = data.slice(index, index + CHUNK_SIZE);
chunk.forEach(item => processDataItem(item));
index += CHUNK_SIZE;
if (index < data.length) {
// 让出主线程
setTimeout(processChunk, 0);
}
}
processChunk();
}CLS(累积布局偏移)
定义
CLS 测量页面加载过程中元素位置的意外移动。用户的视觉体验会因布局偏移而中断。
CLS 评分标准
| 评分 | CLS 值 | 用户体验 |
|---|---|---|
| 优秀 | <= 0.1 | 几乎无感知 |
| 需改进 | 0.1 - 0.25 | 有轻微移动 |
| 差 | > 0.25 | 明显跳动 |
常见 CLS 原因及修复
html
<!-- 1. 图片没有尺寸 → 添加 width/height -->
<!-- 错误 -->
<img src="photo.jpg" alt="照片" loading="lazy">
<!-- 正确 -->
<img src="photo.jpg" alt="照片" width="800" height="400" loading="lazy">
<!-- 2. 动态注入内容 → 预留空间 -->
<!-- 错误:广告加载后推开内容 -->
<div id="ad-slot"></div>
<!-- 正确:预留固定空间 -->
<div id="ad-slot" style="min-height: 250px;"></div>
<!-- 3. Web 字体导致 FOIT → 使用 font-display -->
<style>
@font-face {
font-family: 'CustomFont';
src: url('/fonts/custom.woff2') format('woff2');
font-display: swap; /* 字体加载前使用后备字体 */
}
</style>
<!-- 4. 动态内容 → 使用 CSS aspect-ratio -->
<div style="aspect-ratio: 16/9; background: #f0f0f0;">
<!-- 内容加载前保持比例 -->
</div>CSS 解决方案
css
/* 为图片预留空间 */
.image-placeholder {
aspect-ratio: 16 / 9;
background: #f0f0f0;
overflow: hidden;
}
.image-placeholder img {
width: 100%;
height: 100%;
object-fit: cover;
}
/* 为广告预留空间 */
.ad-slot {
min-height: 250px;
width: 300px;
}
/* 字体加载优化 */
@font-face {
font-family: 'CustomFont';
font-display: swap; /* swap | optional | fallback | block */
}Lighthouse 评分
Lighthouse 性能分类
| 类别 | 权重 | 指标 |
|---|---|---|
| FCP | 15% | First Contentful Paint |
| LCP | 25% | Largest Contentful Paint |
| TBT | 25% | Total Blocking Time |
| CLS | 15% | Cumulative Layout Shift |
| SI | 15% | Speed Index |
| TTI | 5% | Time to Interactive |
运行 Lighthouse
bash
# 使用 Chrome DevTools
# 1. 打开 Chrome DevTools → Lighthouse
# 2. 选择 Performance 类别
# 3. 点击 Analyze page load
# 使用 CLI
npx lighthouse https://example.com --output html --output-path ./report.html
# 使用 npm 包
npm install -g lighthouse
lighthouse https://example.com --view实战示例:全面优化
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Core Web Vitals 优化示例</title>
<!-- LCP 优化:内联关键 CSS -->
<style>
body { margin: 0; font-family: system-ui, sans-serif; }
.hero { position: relative; aspect-ratio: 2/1; background: #f0f0f0; overflow: hidden; }
.hero img { width: 100%; height: 100%; object-fit: cover; }
.content { max-width: 800px; margin: 0 auto; padding: 2rem; }
.card { aspect-ratio: 4/3; background: #f0f0f0; overflow: hidden; }
.card img { width: 100%; height: 100%; object-fit: cover; }
</style>
<!-- LCP 优化:预加载首屏图片 -->
<link rel="preload" href="/images/hero.webp" as="image" fetchpriority="high">
</head>
<body>
<!-- CLS 优化:使用 aspect-ratio 预留空间 -->
<div class="hero">
<img src="/images/hero.webp" alt="首屏横幅" fetchpriority="high" width="1200" height="600" />
</div>
<main class="content">
<h1>Core Web Vitals 优化</h1>
<p>本页面针对 LCP、INP 和 CLS 进行了全面优化。</p>
<!-- CLS 优化:为图片预留空间 + 懒加载 -->
<div class="grid">
<div class="card">
<img src="/images/card-1.webp" alt="卡片1" width="400" height="300" loading="lazy" decoding="async" />
</div>
<div class="card">
<img src="/images/card-2.webp" alt="卡片2" width="400" height="300" loading="lazy" decoding="async" />
</div>
</div>
</main>
<!-- INP 优化:脚本延迟加载 -->
<script defer src="/js/app.js"></script>
<script defer src="/js/analytics.js"></script>
</body>
</html>注意事项
- 在真实环境中测试:实验室数据与真实用户数据可能有差异
- 关注移动端数据:大多数用户的设备性能低于开发机
- LCP 不是唯一的加载指标:同时关注 FCP 和 TTI
- CLS 关注整个生命周期:不仅是页面加载时
- 定期监控:使用 Google Search Console 监控 Core Web Vitals 数据
最佳实践
- LCP:预加载关键资源、优化服务器响应、使用现代图片格式
- INP:拆分长任务、优化事件处理、减少主线程工作
- CLS:为图片/视频设置尺寸、使用 aspect-ratio、font-display: swap
- 使用 Lighthouse 定期审计页面性能
- 使用 Chrome DevTools Performance 面板定位瓶颈
- 使用 Google Search Console 监控真实用户数据
下一节
继续学习:XSS 防护