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

フロントエンド性能:Core Web Vitals 実践

Choyeon
Choyeon
2026年9月15日 1 分で読了 294 閲覧
436 字 2,421 文字 更新日 2026年11月8日
フロントエンド性能:Core Web Vitals 実践
目次

Frontend Performance: Core Web Vitals in Practice

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

筆者について

投票

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

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

コメント (1)

0 / 3000
像素小贩
像素小贩pixelart.studio2026年9月21日

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

関連記事

Astro 静的サイト:アイランドアーキテクチャ & コンテンツコレクション

Astro 静的サイト:アイランドアーキテクチャ & コンテンツコレクション

Astroの革新:最小JSのアイランドアーキテクチャ、型安全なMarkdown/MDXのコンテンツコレクション、ゼロJSの高速静的サイト構築。

1 分で読了
CSS Container Queries 完全ガイド

CSS Container Queries 完全ガイド

モダンCSSの2大レスポンシブ機能:親コンテナ寸法に応じるContainer Queries、子孫要素の状態で親をスタイルする:has()セレクタ。

1 分で読了
PWA オフラインアプリ実践:Service Worker + IndexedDB + Background Sync

PWA オフラインアプリ実践:Service Worker + IndexedDB + Background Sync

インストール可能・オフラインファーストなPWAを段階的構築:Service Worker キャッシュ戦略(Cache First / Stale-While-Revalidate)、構造化ローカルデータ用IndexedDBラッパー、ネットワーク復旧時にオフライン操作を自動リプレイするBackground Syncキュー。完全TypeScriptコード付き。

1 分で読了
Tailwind CSS v4 新機能:Zero-config + CSS ネイティブ変数

Tailwind CSS v4 新機能:Zero-config + CSS ネイティブ変数

Tailwind CSS v4はアーキテクチャ級アップデート:tailwind.config.js を廃止し、ネイティブCSS内の@themeブロックでデザイントークン宣言。@import "tailwindcss" 単一エントリでpostcss設定不要。CSS変数内蔵、Container Queriesネイティブ対応、oxcエンジンで10-40倍高速化、カラー関数簡略化。

1 分で読了
React 18 Hooks ベストプラクティス

React 18 Hooks ベストプラクティス

React 18 は、コンカレントレンダリング、自動バッチング、useTransition、useDeferredValue などの革新的な機能を導入しました。この記事では、useState/useEffect の正しい使い方、useMemo/useCallback の最適化境界、カスタム Hook の設計パターン、コンカレントモードでの古いクロージャや競合状態を回避するための完全なガイドを提供します。

1 分で読了
Vue 3 コンポジション API 実践

Vue 3 コンポジション API 実践

Vue 3 のコンポジション API は、Vue コンポーネントの設計手法を根本的に変えました。複雑な EC サイトのフィルターコンポーネントの構築を通じて、ref/reactive の使い分け、computed/watch の適切な使用方法、カスタム Composable の抽出原則、ライフサイクルフックのタイミング、provide/inject による階層を超えた状態受け渡しの正しい方法を解説します。

1 分で読了