Overview
The browser cannot paint until it has the CSS for the page, it hides text while a web font loads, and a synchronous script stops HTML parsing until it runs. Each of these delays First Contentful Paint and often Largest Contentful Paint. This page covers the three fixes: critical CSS, font loading, and script deferral. Server response time, image formats, and performance budgets live in page-speed.
Load fonts with font-display: swap and self-host
Web fonts block text rendering by default. The browser holds the first paint until the font arrives or a timeout fires.
@font-face {
font-family: "Inter";
src: url("/fonts/inter-var.woff2") format("woff2-variations");
font-display: swap;
font-weight: 100 900;
}font-display: swappaints fallback text immediately, then swaps in the web font.- Self-host fonts to avoid extra DNS, TCP, and TLS round-trips to a third-party origin. If you must use a font CDN, add
preconnectto its origin. - Subset the font to the glyphs the site needs (often Latin). Subsetting a large variable font commonly cuts its size several-fold.
- Use
size-adjust,ascent-override, anddescent-overridein the fallback@font-faceto prevent CLS on swap.
Inline critical CSS and defer the rest
CSS is render-blocking by default. The browser parses the entire stylesheet before painting.
- Extract the above-the-fold CSS with Critical, Critters, or Next.js’s built-in critical CSS plugin.
- Inline it in
<style>inside<head>. Keep it small; about 14 KB of compressed HTML fits in the first TCP round-trip under the common initial congestion window, which is a useful practitioner target. - Defer the rest with
<link rel="preload" as="style" onload="this.rel='stylesheet'">ormedia="print"swap. - Audit unused CSS with Coverage in Chrome DevTools. Sites built on large frameworks often ship mostly unused rules.
Defer JavaScript with async, defer, or interaction-gating
JS parse and execute time blocks the main thread, and the cost is highest on mid-tier phones.
- First-party JS: ship as a module with
type="module"(getsdefersemantics for free). - Analytics, chat widgets, A/B testing, cookie banners: load on
requestIdleCallbackor after the first user interaction. - Audit third-party JS on a schedule. Vendor scripts accumulate, and much of their code never runs on a given page.
- Tree-shake aggressively. Import individual functions (
lodash-esnamed imports) instead of a whole utility library.
Related
- page-speed: TTFB, FCP, images, and budgets
- core-web-vitals
- css
- astro-performance
- optimize-core-web-vitals
- javascript-seo