The score follows the movement, not the other way around
Chasing a PageSpeed number directly produces hacks. Training the critical path produces the number. This article is the training log of a real site going from 69 to 97 performance — every exercise, every measurement.
- Prerendered HTML as the starting position
- The render-blocking CSS diet: 162 KB to 38 KB
- Icon font subsetting: 19 icons, not 512 KB
- AVIF hero images and fetchpriority
- Content-hashed bundles with immutable caching
Abstract: On-site SEO in 2026 is mostly a performance discipline, and performance is mostly a critical-path discipline. This article is a training log, not a theory piece: the site you are reading went from a 69 to a 97 performance score, from 1.4 s to 0.6 s first paint, from a 5-second to a 1.2-second LCP — with no redesign. The program: prerender everything you can, put the render-blocking CSS on a diet, serve images at the size they are displayed, and let the browser cache like it means it. The score was never the target. It was the side effect.
Nobody gets strong by staring at the scoreboard. A PageSpeed score is a measurement of movements your site performs every time a browser walks in: how fast it paints, how much it ships, how honestly it declares what is coming. You do not train the number. You train the movement — and the number follows.
1. The Scoreboard Is Not the Workout
PageSpeed Insights hands you four numbers that matter: First Contentful Paint, Largest Contentful Paint, Cumulative Layout Shift, Total Blocking Time. It is tempting to treat them as the goal. They are diagnostics — the gym mirror, not the muscle.
This matters because chasing the score directly produces hacks: inlining everything, lazy-loading the hero, stripping features on the audit’s user agent. Chasing the movement — what the browser must do before it can paint — produces durable speed that happens to score well.
The starting position matters more than any single exercise. A prerendered site — plain HTML files built ahead of time and served from a CDN — begins every request already ahead: no server think-time, no hydration cliff, no JavaScript standing between the visitor and the first byte of content. This site is prerendered by Astro, and its baseline audit still said 69.
A prerendered site with a 69 is not a rendering problem. It is a payload problem.
2. Compound Lifts: the Critical Path
The critical path is the compound lift of web performance: everything the browser must download, parse, and apply before it may paint a single pixel. Here, that was one CSS bundle — 162 KB gzipped — plus a render-blocking request chain to Google Fonts.
The audit found where the weight was hiding. Font Awesome Pro: 512 KB of CSS (100 KB gzipped) and roughly 850 KB of font binaries. The whole site uses nineteen icons.
That ratio — nineteen icons, half a megabyte of CSS — is worth sitting with. It is the default state of most sites: frameworks and icon packs shipped whole, consumed at one percent.
The exercises, in order of weight moved:
| Exercise | Before | After | How |
|---|---|---|---|
| Icon subset | 512 KB CSS + ~850 KB fonts | 1.6 KB CSS + 5 KB fonts | Scan source for used classes, subset the woff2 to those 19 glyphs |
| Self-hosted webfonts | render-blocking third-party chain (~490 ms) | same-origin, zero external requests | Vendor the Google Fonts CSS + woff2 files |
| Framework purge | Bootstrap 31 KB gz | ~8 KB gz | PurgeCSS against the actual templates, safelist for runtime classes |
| Animation subset | every animate.css keyframe | the 3 the site uses | Extract only what the markup references |
Result: the render-blocking path is now a single same-origin stylesheet, 37.8 KB gzipped. First paint moved from 1.4 s to 0.6 s on desktop, and the improvement is structural — there is simply less standing between the request and the pixel.
The trap: bundling and minification feel like the workout. They are the warm-up. Minifying 512 KB of icon CSS you don’t use produces 500 KB of minified CSS you don’t use. Subtract first, compress second.
3. Accessories: Images
LCP has a simpler personality than its reputation suggests: it is almost always one image, and that image is almost always too big.
Here it was the hero portrait — a 2.3 MB PNG, shipped at 1024×1536, displayed at 282×422. The browser downloaded eleven times more pixels than it painted. LCP: 5 seconds.
The fix is mechanical once you see it that way:
serve the display size -> srcset 400/640/960 + sizes
serve the modern format -> <picture> AVIF first, WebP fallback
declare the priority -> fetchpriority="high" on the LCP image only
reserve the space -> width/height attributes (CLS insurance)
defer everything else -> loading="lazy" below the fold
The same portrait now arrives as a 37 KB AVIF. A 543 KB screenshot in a blog article became a 58 KB WebP, pixel-identical at its rendered size. LCP: 1.2 seconds. Nothing about the design changed — only the honesty of the delivery.
4. Conditioning: Caching and the Network
The first three exercises speed up the first visit. Conditioning is about every visit after that, and it is where advanced browser networking pays off quietly.
The core move is content-hashed filenames plus immutable caching. Each bundle’s name contains a
digest of its own bytes — site.7e2d1a25.min.css — so the URL changes whenever the content does.
That makes a one-year Cache-Control: immutable header safe: a stale file can never be served,
because an update is, by definition, a different URL. Repeat visitors re-download exactly nothing.
first visit repeat visit
----------- ------------
HTML ── CDN edge HTML ── CDN edge (revalidated)
site.css ── 37.8 KB gz site.css ── memory cache, 0 bytes
site-core.js── 119 KB site-core.js── memory cache, 0 bytes
hero AVIF ── 37 KB hero AVIF ── disk cache, 0 bytes
fonts ── 5 KB, immutable fonts ── 0 bytes
The rest of the conditioning program comes nearly free on a modern host: HTTP/3 and Brotli from
the CDN, font-display: swap so text never waits for a font file, and no third-party origin left
on the critical path — every preconnect you don’t need is faster than the one you optimized.
Curated Source
Optimize Largest Contentful Paint
The web.dev guidance lands on the same conclusion as any decent training program: there is no single heroic lift. LCP improves when the whole chain improves — document delivery, resource discovery, download size, render order. Program over hack.
"It's rare that a quick fix to a single part of a page will result in a meaningful improvement to LCP."Read the original guide
5. The Clean-Site Dividend
Here is the part the score does not advertise: the same work fixed things that had nothing to do with speed.
Declaring image dimensions for layout stability also ended the aspect-ratio distortions hiding in the CSS. Subsetting the icon font forced an inventory of what the site actually uses. The accessibility audit went from 90 to 100 on the way past — contrast ratios, labels wired to their inputs, heading order — because a performance pass is, in practice, an honesty pass. You read every request, every rule, every tag, and you delete the lies.
Browsers reward that the same way search engines do, and for the same reason: a site that ships only what it means is easier to parse, easier to cache, easier to trust. “Loved by browsers” is not a metaphor. It is a measurable posture.
6. Closing
The final board, same site, same design: performance 69 → 97, accessibility 90 → 100, best practices 77 → 100. First paint 0.6 s. One render-blocking file where there were dozens.
None of it came from optimizing the score. It came from training the movement — subtract the unused, right-size the images, hash the names, and let the browser do what it is built to do. The scoreboard caught up on its own. It always does.