提示:本网站现在为维护调试状态

Frontend Performance: Core Web Vitals in Practice

Choyeon
Choyeon
Sep 15, 2026 1 min read 290 Views
436 words 2,421 chars Updated Nov 8, 2026
Frontend Performance: Core Web Vitals in Practice
Table of contents

Since 2021 Google includes Core Web Vitals in search rankings, making performance a growth lever instead of just UX polish. Three metrics directly capture user perception of load, stability, and responsiveness.

LCP (Largest Contentful Paint) <2.5s

Four LCP factors: slow server response -> CDN/HTTP3/preconnect critical origins. Render-blocking resources -> inline critical CSS / defer the rest. Slow loads -> fetchpriority=high/srcset/AVIF. Client render -> SSR/islands.

import { onCLS, onINP, onLCP, type Metric } from "web-vitals";

const URL = "/api/analytics/vitals";
function send(metric: Metric) {
    const body = JSON.stringify({
        name: metric.name, value: metric.value, rating: metric.rating,
        id: metric.id, url: location.href, ts: Date.now(),
    });
    if (navigator.sendBeacon) navigator.sendBeacon(URL, body);
    else fetch(URL, { body, method: "POST", keepalive: true }).catch(() => {});
}
export function initVitals() {
    if (location.hostname === "localhost") {
        const log = (m: Metric) => console.log(`[vitals] ${m.name}=${Math.round(m.value)} rating=${m.rating}`);
        onLCP(log); onCLS(log); onINP(log); return;
    }
    onLCP(send); onCLS(send); onINP(send);
}

export function scheduleHigh(work: () => void): void {
    if ("scheduler" in window && "postTask" in (window as any).scheduler)
        (window as any).scheduler.postTask(work, { priority: "user-blocking" });
    else if ("requestIdleCallback" in window)
        requestAnimationFrame(() => requestIdleCallback(() => work(), { timeout: 1500 }));
    else setTimeout(work, 0);
}

export function splitTasks(total: number, unit: (i: number) => void, chunk = 25): void {
    let i = 0;
    const pump = (deadline?: any): void => {
        const rem = typeof deadline !== "undefined" && deadline.timeRemaining ? deadline : { timeRemaining: () => 8 };
        while (i < total && rem.timeRemaining() > 1 && (i % chunk !== 0 || i === 0)) unit(i++);
        if (i < total) "requestIdleCallback" in window ? requestIdleCallback(pump) : setTimeout(pump, 0);
    };
    "requestIdleCallback" in window ? requestIdleCallback(pump) : pump();
}

export function throttle<T extends (...a: any[]) => void>(fn: T, wait = 150, opts: { leading?: boolean; trailing?: boolean } = {}): T {
    const { leading = true, trailing = true } = opts;
    let last = 0, tId: any = null, lastArgs: any[] | null = null;
    return function (this: any, ...args: any[]) {
        const now = Date.now();
        if (!last && !leading) last = now;
        const remaining = wait - (now - last);
        lastArgs = args;
        if (remaining <= 0) {
            if (tId) { clearTimeout(tId); tId = null; }
            last = now; fn.apply(this, args); lastArgs = null;
        } else if (trailing && !tId) {
            tId = setTimeout(() => {
                last = leading ? Date.now() : 0; tId = null;
                if (lastArgs) { fn.apply(this, lastArgs); lastArgs = null; }
            }, remaining);
        }
    } as T;
}

CLS <0.1 & INP <200ms

CLS culprits: images/videos without explicit dimensions, font swap jitter, unbanners/dynamic inserts without reserved height. INP replaces FID - measures every input-to-paint; >50ms Long Tasks the primary optimization target.

Metric Green Target Top Culprit #1 Top Culprit #2 Primary Fixes
LCP <2.5s Heavy hero images Slow TTFB preconnect, AVIF, fetchpriority
CLS <0.1 Images without w/h Font swap reflow Declare dims, font-display:optional
INP <200ms Long task blocks main Heavy style/layout postTask, rIC splitting
TTFB <800ms Slow backend queries No edge caching CDN cache, SSR streaming

Best Practices

Ship the web-vitals library for Real User Monitoring (RUM). Local Lighthouse lab data isn't enough. Always budget 3-10x headroom because mobile devices are slower by that factor.

X微博Telegram

About the author

Poll

你最希望 Rosetta 优先加入哪项功能?

社区投票(演示数据,可后台删除)

Comments (1)

0 / 3000
像素小贩
像素小贩pixelart.studioSep 21, 2026

看到博主推荐的这个 UI 组件库了,之前一直在纠结选哪个,试了一下确实不错,文档也很友好!

Related posts

Astro Deep Dive: Islands Architecture & Content Collections

Astro Deep Dive: Islands Architecture & Content Collections

Astro innovations: Islands Architecture for minimal JS with partial hydration, Content Collections for type-safe Markdown/MDX management, ultra-fast zero-JS static sites.

1 min read
Complete Guide to CSS Container Queries

Complete Guide to CSS Container Queries

Modern responsive CSS pillars: Container Queries for component-level responsiveness based on parent size (not viewport), plus :has() parent selector for ancestor styling based on descendants.

1 min read
PWA Offline App in Practice: Service Worker + IndexedDB + Background Sync

PWA Offline App in Practice: Service Worker + IndexedDB + Background Sync

Build installable, offline-first Progressive Web Apps: Service Worker caching strategies (Cache First, Stale-While-Revalidate), IndexedDB wrapper for structured local data, Background Sync queue that replays offline operations when network returns. Full TypeScript code included.

1 min read
Tailwind CSS v4: Zero-config + CSS-native Variables

Tailwind CSS v4: Zero-config + CSS-native Variables

Tailwind CSS v4 is an architectural upgrade: goodbye tailwind.config.js, declare design tokens in @theme blocks inside native CSS files. Single @import "tailwindcss" entry replaces postcss.config; built-in CSS vars, native container queries, oxc engine 10-40x faster, simplified color functions.

1 min read
React 18 Hooks Best Practices

React 18 Hooks Best Practices

React 18 introduces revolutionary features like concurrent rendering, automatic batching, useTransition, and useDeferredValue. This article systematically covers correct useState/useEffect usage, useMemo/useCallback optimization boundaries, custom Hook design patterns, and a complete guide to avoiding stale closures, race conditions, and other pitfalls in concurrent mode.

1 min read
Vue 3 Composition API in Practice

Vue 3 Composition API in Practice

Vue 3's Composition API fundamentally changed how Vue components are organized. Through building a complex e-commerce filter component, this article demonstrates ref vs reactive choices, proper computed/watch usage, custom Composable extraction principles, lifecycle hook timing, and the correct approach to cross-layer state via provide/inject.

1 min read