Frontend Performance Metrics: LCP, FID, CLS, and Core Web Vitals

性能优化(Updated May 14, 2026)

Core Web Vitals: Google's Performance Bar

In 2020 Google introduced Core Web Vitals as a search ranking signal:

Metric Meaning Good Needs work Poor
LCP Largest Contentful Paint ≤2.5s ≤4s >4s
INP Interaction to Next Paint ≤200ms ≤500ms >500ms
CLS Cumulative Layout Shift ≤0.1 ≤0.25 >0.25

As of March 2024, INP officially replaced FID as the interactivity metric.


LCP: Largest Contentful Paint

What is LCP?

LCP measures when the largest visible content element renders—typically:

  • Images (<img>)
  • Background images (CSS background-image)
  • Text blocks (<p>, <h1>)
  • <video> poster frames

Four phases of LCP

TTFB → resource load delay → resource load time → element render delay
  ↑          ↑              ↑              ↑
Server      <link rel="preload">    CDN distance     critical CSS/fonts
response    priority/preload        /compression     blocking render

Optimization strategies

1. Optimize TTFB

ToolsKu TTFB: ~50ms (CDN serves static HTML directly)
Typical SSR site: 200–500ms (server render per request)

Static export + CDN naturally yields very low TTFB.

2. Preload critical resources

<link rel="preload" href="/fonts/geist-sans.woff2" as="font" type="font/woff2" crossorigin />
<link rel="preload" href="/i18n/toolClients/zh-CN.json" as="fetch" crossorigin />

ToolsKu preloads tool client JSON in layout.tsx.

3. Font optimization

// next.config.ts - npm package fonts instead of Google Fonts CDN
// Avoid: fonts.googleapis.com often ECONNRESET in some regions
import { GeistSans } from 'geist/font/sans';

4. Image optimization

For tool sites, LCP is often hero text—not images. Blog images still matter:

<img
  src="photo.webp"
  loading="eager"     <!-- LCP image: not lazy -->
  fetchpriority="high"
  decoding="async"
/>

INP: Interaction to Next Paint

From FID to INP

FID only measured first input delay—not total interaction time. INP measures the full cycle of interactions:

User click/keypress
     ↓
Input event starts
     ↓
Event handlers (JS)
     ↓
Style/layout
     ↓
Paint
     ↓
INP = time from input start to paint complete

Common INP issues

Long main-thread tasks

// Bad: sync heavy work blocks the main thread
function processData(data) {
  const result = heavyComputation(data); // blocks ~500ms
  updateUI(result);
}

// Good: chunk or use a Worker
async function processData(data) {
  const result = await processInWorker(data);
  updateUI(result);
}

React re-renders

// Bad: full list re-render on filter
setFilter(keyword); // 1000 tool cards re-render

// Good: virtualization + useMemo
const filtered = useMemo(
  () => tools.filter(t => t.name.includes(keyword)),
  [tools, keyword]
);

ToolsKu INP optimizations

  1. Pre-built search index: tools-search/zh-CN.json at build time—no scanning all tools at runtime
  2. WASM in Workers: FFmpeg.wasm runs off the main thread
  3. React.lazy: Tool page components load on demand, smaller main bundle

CLS: Cumulative Layout Shift

How CLS is computed

CLS = Σ (impact fraction × distance fraction)

Impact fraction: how much of the viewport shifted
Distance fraction: how far elements moved relative to the viewport

Common CLS sources

Source Example Fix
Images without dimensions <img src="..."> width/height or aspect-ratio
Late-injected content Ads/recommendations Reserve space (min-height)
Web font FOIT Text invisible then visible font-display: swap + metric fallbacks
Async UI Search box/modal late render min-height reservation

ToolsKu CLS optimizations

/* Fixed nav height to avoid jump on load */
nav[data-tools-nav] {
  /* height set via CSS variable after JS measure */
}

/* Fixed footer height */
:root {
  --site-footer-h: 33px;
}
body {
  padding-bottom: var(--site-footer-h);
}

Measurement Tools

Lab data

Tool Use
Lighthouse CI automated audits
Chrome DevTools Performance Frame-by-frame analysis
WebPageTest Multi-location/device testing

Field data

Tool Use
Chrome UX Report (CrUX) Real-user data from Google
web-vitals JS library Self-hosted RUM
Google Search Console Core Web Vitals report

Collecting with web-vitals

import { onLCP, onINP, onCLS } from 'web-vitals';

onLCP((metric) => {
  gtag('event', 'web_vital', {
    name: 'LCP',
    value: metric.value,
    rating: metric.rating,
  });
});

onINP((metric) => { /* ... */ });
onCLS((metric) => { /* ... */ });

ToolsKu Performance Numbers

Lighthouse (simulated 4× slowdown, desktop):

Metric Value Rating
Performance 95 🟢
LCP 1.2s 🟢 Good
INP 80ms 🟢 Good
CLS 0.02 🟢 Good
TTFB 50ms 🟢 Good
FCP 0.8s 🟢 Good
TTI 1.5s 🟢 Good

Where the wins come from

  1. Pure static HTML: CDN serves pages directly—minimal TTFB
  2. No client render wait: Server Components pre-rendered
  3. Lazy WASM: FFmpeg (~30MB) only on video tool pages
  4. Local fonts: No Google Fonts CDN latency/failures
  5. Preload critical assets: Search index, tool client JSON

Optimization Checklist

LCP

  • Identify LCP element (DevTools → LCP marker)
  • Preload LCP images/fonts
  • CDN deploy to lower TTFB
  • Inline critical CSS for above-the-fold
  • fetchpriority="high" on LCP resources

INP

  • Find long tasks (DevTools → Long Tasks)
  • Move compute to Web Workers
  • requestIdleCallback for non-urgent work
  • React: useMemo / useCallback / virtualization

CLS

  • Images: width + height or aspect-ratio
  • Fonts: font-display: swap + size-adjust
  • Reserve space for dynamic content
  • Avoid document.body.appendChild layout shifts

Summary

Core Web Vitals are more than SEO—they measure real user experience. ToolsKu combines static export + CDN + preload + Worker offload + local fonts to hit LCP < 1.5s, INP < 100ms, and CLS < 0.05.

Use the OG preview tool to check share cards and HTTP headers analyzer to verify cache policies.

Try these browser-local tools — no sign-up required →

#性能#Core Web Vitals#LCP#INP#CLS