performance-and-web-vitals

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Performance and Web Vitals

性能与Web Vitals

Run a Lighthouse Audit

运行Lighthouse审计

bash
undefined
bash
undefined

CLI audit — outputs JSON and HTML report

CLI audit — outputs JSON and HTML report

npx lighthouse https://example.com --output html --output-path ./lighthouse-report.html
npx lighthouse https://example.com --output html --output-path ./lighthouse-report.html

Headless, useful in CI

Headless, useful in CI

npx lighthouse https://example.com --chrome-flags="--headless" --output json --output-path ./report.json
npx lighthouse https://example.com --chrome-flags="--headless" --output json --output-path ./report.json

Audit specific categories only

Audit specific categories only

npx lighthouse https://example.com --only-categories=performance,accessibility,seo

Or open Chrome DevTools → Lighthouse tab → Analyse page load.

**Target scores:**
| Category | Target |
|---|---|
| Performance | ≥ 90 |
| Accessibility | 100 |
| Best Practices | ≥ 95 |
| SEO | ≥ 95 |

---
npx lighthouse https://example.com --only-categories=performance,accessibility,seo

或者打开Chrome开发者工具 → Lighthouse标签页 → 分析页面加载。

**目标评分:**
| 分类 | 目标值 |
|---|---|
| 性能 | ≥ 90 |
| 可访问性 | 100 |
| 最佳实践 | ≥ 95 |
| SEO | ≥ 95 |

---

Core Web Vitals

Core Web Vitals核心指标

LCP — Largest Contentful Paint

LCP — Largest Contentful Paint(最大内容绘制)

How fast does the main content appear?
Target: ≤ 2.5s
LCP measures when the largest visible element (hero image, heading, video poster) renders. It is the user's perception of "did the page load?"
Common causes and fixes:
CauseFix
Unoptimised hero imageUse WebP/AVIF, correct size,
fetchpriority="high"
Image not preloaded
<link rel="preload" as="image" href="hero.webp">
Render-blocking CSS/JSDefer non-critical JS, inline critical CSS
Slow server responseCDN, caching headers, edge delivery
Web font blocking render
font-display: swap
or
optional
html
<!-- Preload LCP image -->
<link rel="preload" as="image" href="hero.webp" fetchpriority="high">

<!-- LCP image: no lazy loading -->
<img src="hero.webp" alt="..." fetchpriority="high" width="1200" height="600">
Never use
loading="lazy"
on the LCP image — it delays the most important render.

主内容多久能显示出来?
目标值:≤ 2.5秒
LCP用于衡量最大可见元素(首屏图片、标题、视频封面)的渲染时间,它是用户感知“页面是否加载完成”的关键指标。
常见问题及修复方案:
问题原因修复方法
首屏图片未优化使用WebP/AVIF格式、设置正确尺寸、添加
fetchpriority="high"
图片未预加载添加
<link rel="preload" as="image" href="hero.webp">
CSS/JS阻塞渲染延迟非关键JS加载、内联关键CSS
服务器响应缓慢使用CDN、配置缓存头、边缘分发
Web字体阻塞渲染设置
font-display: swap
optional
html
<!-- 预加载LCP图片 -->
<link rel="preload" as="image" href="hero.webp" fetchpriority="high">

<!-- LCP图片:禁止懒加载 -->
<img src="hero.webp" alt="..." fetchpriority="high" width="1200" height="600">
切勿在LCP图片上使用
loading="lazy"
——这会延迟最重要元素的渲染。

CLS — Cumulative Layout Shift

CLS — Cumulative Layout Shift(累积布局偏移)

Does content jump around while loading?
Target: ≤ 0.1
CLS measures unexpected layout shifts — content moving after it has rendered. Caused by images without dimensions, late-loading ads, fonts swapping, or dynamic content injected above existing content.
Common causes and fixes:
CauseFix
Images without width/heightAlways set
width
and
height
on
<img>
Web font swapUse
font-display: optional
or preload fonts
Dynamic content above foldReserve space with
min-height
on containers
Late-loading ads or embedsReserve fixed dimensions for ad slots
Animations that shift layoutAnimate
transform
only, never
top/left/width/height
html
<!-- Always include dimensions -->
<img src="product.jpg" width="400" height="300" alt="...">
css
/* Reserve space for dynamic content */
.ad-slot { min-height: 250px; }

/* Animate transform, not layout properties */
.slide-in { transform: translateY(0); transition: transform 300ms; }

页面加载时内容是否会突然跳动?
目标值:≤ 0.1
CLS用于衡量意外的布局偏移——内容渲染后发生移动。通常由未设置尺寸的图片、延迟加载的广告、字体切换,或在现有内容上方注入动态内容导致。
常见问题及修复方案:
问题原因修复方法
图片未设置宽高始终为
<img>
标签设置
width
height
Web字体切换使用
font-display: optional
或预加载字体
首屏上方的动态内容为容器设置
min-height
预留空间
延迟加载的广告或嵌入内容为广告位预留固定尺寸
导致布局偏移的动画仅对
transform
设置动画,切勿使用
top/left/width/height
html
<!-- 始终包含尺寸属性 -->
<img src="product.jpg" width="400" height="300" alt="...">
css
/* 为动态内容预留空间 */
.ad-slot { min-height: 250px; }

/* 对transform设置动画,而非布局属性 */
.slide-in { transform: translateY(0); transition: transform 300ms; }

INP — Interaction to Next Paint

INP — Interaction to Next Paint(交互到下一次绘制的时间)

How quickly does the page respond to user input?
Target: ≤ 200ms
INP measures the delay between a user interaction (click, tap, keyboard) and the next visual update. High INP makes the UI feel sluggish or frozen.
Common causes and fixes:
CauseFix
Heavy JS on main threadBreak into smaller tasks, use
requestIdleCallback
Large event handlersDebounce/throttle scroll and resize handlers
Synchronous DOM updatesBatch DOM writes with
requestAnimationFrame
Third-party scripts blockingLoad third-party scripts with
async
or
defer
React re-rendersMemoize with
useMemo
,
useCallback
,
React.memo

页面响应用户输入的速度有多快?
目标值:≤ 200毫秒
INP用于衡量用户交互(点击、轻触、键盘操作)与下一次视觉更新之间的延迟。高INP会让UI感觉卡顿或冻结。
常见问题及修复方案:
问题原因修复方法
主线程JS负载过重拆分为更小任务、使用
requestIdleCallback
大型事件处理器对滚动和 resize 事件处理器进行防抖/节流
同步DOM更新使用
requestAnimationFrame
批量处理DOM写入
第三方脚本阻塞使用
async
defer
加载第三方脚本
React重复渲染使用
useMemo
useCallback
React.memo
进行 memoize 优化

Images

图片优化

Images are the single biggest performance lever on most pages.
html
<!-- Modern formats with fallback -->
<picture>
  <source srcset="image.avif" type="image/avif">
  <source srcset="image.webp" type="image/webp">
  <img src="image.jpg" width="800" height="600" alt="..." loading="lazy">
</picture>

<!-- Responsive images -->
<img
  srcset="image-400.webp 400w, image-800.webp 800w, image-1200.webp 1200w"
  sizes="(max-width: 600px) 100vw, 50vw"
  src="image-800.webp"
  alt="..."
  width="800"
  height="600"
  loading="lazy"
>
Rules:
  • Always set
    width
    and
    height
    — prevents CLS
  • Use
    loading="lazy"
    below the fold, never on LCP image
  • Serve WebP or AVIF — typically 30–50% smaller than JPEG
  • Size images to their display size — do not serve 2000px image for a 400px slot
  • Use a CDN with automatic format conversion where possible

图片是大多数页面中影响性能的最大因素。
html
<!-- 现代格式带降级方案 -->
<picture>
  <source srcset="image.avif" type="image/avif">
  <source srcset="image.webp" type="image/webp">
  <img src="image.jpg" width="800" height="600" alt="..." loading="lazy">
</picture>

<!-- 响应式图片 -->
<img
  srcset="image-400.webp 400w, image-800.webp 800w, image-1200.webp 1200w"
  sizes="(max-width: 600px) 100vw, 50vw"
  src="image-800.webp"
  alt="..."
  width="800"
  height="600"
  loading="lazy"
>
规则:
  • 始终设置
    width
    height
    ——防止CLS
  • 仅对首屏以下的图片使用
    loading="lazy"
    ,切勿用于LCP图片
  • 提供WebP或AVIF格式——通常比JPEG小30–50%
  • 图片尺寸匹配显示尺寸——不要为400px的容器提供2000px的图片
  • 尽可能使用支持自动格式转换的CDN

Fonts

字体优化

Web fonts block rendering if not handled correctly.
html
<!-- Preconnect to font origin -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

<!-- Preload critical font file -->
<link rel="preload" href="/fonts/brand.woff2" as="font" type="font/woff2" crossorigin>
css
@font-face {
  font-family: 'Brand';
  src: url('/fonts/brand.woff2') format('woff2');
  font-display: swap;     /* show fallback immediately, swap when loaded */
  /* font-display: optional; — never swap, use fallback if not cached */
}
  • font-display: swap
    — good for headings, acceptable CLS
  • font-display: optional
    — zero CLS, font only used if cached (best for body text)
  • Subset fonts to the characters actually used — reduces file size by 60–80%

处理不当的Web字体会阻塞页面渲染。
html
<!-- 预连接到字体源 -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

<!-- 预加载关键字体文件 -->
<link rel="preload" href="/fonts/brand.woff2" as="font" type="font/woff2" crossorigin>
css
@font-face {
  font-family: 'Brand';
  src: url('/fonts/brand.woff2') format('woff2');
  font-display: swap;     /* 立即显示 fallback 字体,加载完成后替换 */
  /* font-display: optional; — 绝不替换,仅在缓存时使用自定义字体 */
}
  • font-display: swap
    ——适合标题,可接受轻微CLS
  • font-display: optional
    ——零CLS,仅当字体已缓存时使用(适合正文)
  • 对字体进行子集化,仅包含实际使用的字符——可减少60–80%的文件大小

JavaScript

JavaScript优化

html
<!-- Defer non-critical scripts -->
<script src="analytics.js" defer></script>
<script src="chat-widget.js" async></script>

<!-- Module scripts are deferred by default -->
<script type="module" src="app.js"></script>
  • defer
    : executes after HTML parsed, in order — use for most scripts
  • async
    : executes as soon as downloaded, out of order — use for independent scripts (analytics)
  • Never block the main thread with synchronous
    <script>
    in
    <head>

html
<!-- 延迟非关键脚本加载 -->
<script src="analytics.js" defer></script>
<script src="chat-widget.js" async></script>

<!-- 模块脚本默认延迟加载 -->
<script type="module" src="app.js"></script>
  • defer
    :HTML解析完成后按顺序执行——适用于大多数脚本
  • async
    :下载完成后立即执行,顺序不确定——适用于独立脚本(如分析脚本)
  • 切勿在
    <head>
    中使用同步
    <script>
    阻塞主线程

Lighthouse CI (automated audits)

Lighthouse CI(自动化审计)

Run Lighthouse in CI to catch regressions before deployment.
bash
undefined
在CI中运行Lighthouse,在部署前捕获性能退化问题。
bash
undefined

Install

安装

npm install -g @lhci/cli
npm install -g @lhci/cli

Run

运行

lhci autorun --upload.target=temporary-public-storage

```yaml
lhci autorun --upload.target=temporary-public-storage

```yaml

.lighthouserc.json

.lighthouserc.json

{ "ci": { "assert": { "assertions": { "categories:performance": ["warn", { "minScore": 0.9 }], "categories:accessibility": ["error", { "minScore": 1.0 }], "categories:seo": ["warn", { "minScore": 0.95 }] } } } }

---
{ "ci": { "assert": { "assertions": { "categories:performance": ["warn", { "minScore": 0.9 }], "categories:accessibility": ["error", { "minScore": 1.0 }], "categories:seo": ["warn", { "minScore": 0.95 }] } } } }

---

Review Checklist

审核清单

  • Lighthouse performance score ≥ 90
  • Lighthouse accessibility score = 100
  • LCP ≤ 2.5s — LCP image preloaded, no
    loading="lazy"
    on it
  • CLS ≤ 0.1 — all images have
    width
    and
    height
    , no layout-shifting animations
  • INP ≤ 200ms — no heavy synchronous JS on main thread
  • Images served as WebP or AVIF with correct dimensions
  • loading="lazy"
    on all below-fold images
  • Web fonts use
    font-display: swap
    or
    optional
  • Non-critical JS loaded with
    defer
    or
    async
  • Lighthouse CI configured to catch regressions in deployment pipeline
  • Lighthouse性能评分 ≥ 90
  • Lighthouse可访问性评分 = 100
  • LCP ≤ 2.5秒——LCP图片已预加载,未使用
    loading="lazy"
  • CLS ≤ 0.1——所有图片均设置
    width
    height
    ,无布局偏移动画
  • INP ≤ 200毫秒——主线程无重型同步JS
  • 图片以WebP或AVIF格式提供,尺寸正确
  • 所有首屏以下图片使用
    loading="lazy"
  • Web字体使用
    font-display: swap
    optional
  • 非关键JS通过
    defer
    async
    加载
  • 已配置Lighthouse CI在部署流程中捕获性能退化问题