2 min read

Cutting a 4.2s LCP to 900ms without a rewrite

A partner brought us a marketing site with a 4.2 second Largest Contentful Paint on a mid-range Android phone. The brief was a rebuild. We spent two days measuring instead, and shipped 900ms on the existing codebase.

Measure the thing, not the feeling

The first useful move is finding out which element is actually the LCP candidate. It is very often not the one everybody assumes.

new PerformanceObserver((list) => {
  const entry = list.getEntries().at(-1);
  console.log(entry.element, entry.startTime);
}).observe({ type: 'largest-contentful-paint', buffered: true });

On this site it was the hero heading, not the hero image — which meant every hour that had gone into image compression had been spent on the wrong thing. The heading was late because it waited on a webfont that waited on a stylesheet that waited on a render-blocking script in the head.

What actually moved the number

  1. Self-hosted the variable font and preloaded it. Two round trips to a font CDN disappeared. −1.4s.
  2. Set font-display: swap. The heading now paints in a fallback face immediately rather than holding the frame. −0.9s.
  3. Deferred the consent script. It was blocking parse in the head to save a flash that nobody had ever complained about. −0.7s.
  4. Inlined the critical CSS for the header and hero. −0.3s, and the last one worth doing.

What we did not do

We did not rewrite the site, change the framework, or add a caching plugin. None of those would have touched the font chain, and two of them would have added a migration risk to a site that was converting fine.


The general lesson is dull and holds up almost every time: a rebuild is a way of avoiding the measurement, and the measurement is usually cheaper than the rebuild.

Share

X LinkedIn

Get Started Today


Focus on what matters and make smarter, faster decisions with NovemBit. Stop getting lost in the sea of information.

Let’s connect

Tell us what needs building. We reply within two working days with scope, timeline and a number.

Select all that apply.

Prefer email? [email protected]