Blog ·

Our fade-in animation hid our own LCP

A monitoring company's homepage measured 2.31 s LCP on its first build. The culprit was a 0.7-second fade-in, and the fix was deleting it.

Our website has a small bar along the bottom that measures the page you’re reading, live in your browser: TTFB, FCP, LCP, CLS, bytes transferred and cookies (always zero). We built it to show off. On the very first build it showed us something embarrassing: LCP 2.31 s on desktop. On mobile it was 144 ms.

What happened

The hero headline faded in: opacity: 0 to 1 over 0.7 seconds, after a short stagger delay. It looked nice. But Chrome’s Largest Contentful Paint ignores elements that are invisible when they first paint. The headline, which was the biggest thing on screen, was painted at opacity: 0, so it never became an LCP candidate. LCP was reported for whatever else painted, and in that run it landed at 2.31 s.

Two problems in one:

  1. The number was wrong. The visitor saw the headline appear well before 2.31 s, but LCP couldn’t see it. If your RUM dashboard shows strange LCP elements on pages with entrance animations, this may be why.
  2. The experience was slower than it needed to be. The headline was in the very first frame’s HTML, and we were deliberately hiding it for most of a second.

The fix

First we changed the animation to movement only, with no opacity change. The headline became the LCP element at about 140 ms.

Then we deleted the animations altogether. A performance company’s homepage should show its content on the first frame, so there’s no fade, no slide and no stagger. Our only remaining animation is the pulsing dot on the live readout.

We also switched the web fonts to font-display: optional, with the above-the-fold fonts preloaded. If a font hasn’t arrived by first render, that visit uses the fallback font rather than swapping later and shifting the layout. That took our mobile CLS from 0.02 to zero.

The takeaway

Entrance animations on large above-the-fold elements cost you twice: they delay what visitors see, and they can make your LCP measurement point at the wrong element. If you need one, animate transform and never start at opacity: 0. Better still, skip it.