This is the post I’ve been building toward this whole series, honestly. Everything we’ve covered — images, fonts, ads, dynamic content, animations — actually showed up on one real project I worked on last year. I’m not going to name the client, but I will walk through exactly what I found and exactly what I did, in the order I actually did it.
The Starting Point
The site was a content-heavy publisher page — long articles, a handful of display ads, embedded videos, a newsletter signup bar, and a comment section at the bottom. Field data from Search Console showed a CLS of 0.35 on mobile, comfortably in “poor” territory. Desktop wasn’t much better at 0.28.
Step 1: Get a Baseline and Find the Biggest Offenders First
Before touching anything, I ran Lighthouse repeatedly and used Chrome DevTools’ Performance panel to record an actual page load, watching for “Layout Shift” events in the timeline. This is a step I’d genuinely recommend to anyone starting a similar cleanup — don’t guess where the problem is, watch it happen.
Three things jumped out immediately, roughly in order of impact:
- A display ad injected mid-article with no reserved space
- Hero and inline article images missing width/height attributes
- A newsletter signup bar that slid in from the top of the page after a 3-second delay
Step 2: Fix the Ad Slot First
This one alone accounted for the largest chunk of the score. I wrapped the ad slot in a fixed-height container matching the standard IAB medium rectangle size (300×250), with a neutral background color as a placeholder.
.ad-slot-inline {
min-height: 250px;
width: 300px;
background: #f5f5f5;
}
Result after this single change: CLS dropped from 0.35 to roughly 0.19 on mobile. That’s more than half the total problem, from one fix.
Step 3: Add Dimensions to Every Image
Next, I went through the article template and made sure every <img> tag had explicit width and height attributes, plus aspect-ratio in the CSS as a responsive backup. This was tedious but mechanical — no clever decisions required, just discipline.
Result: down to approximately 0.11.
Step 4: Fix the Newsletter Bar
The newsletter signup bar was the trickiest one, actually, because it wasn’t obviously “wrong” — it just hadn’t been built with layout stability in mind at all. It was injected at the top of the document flow after a delay, pushing the entire article down.
I made two changes: switched it to position: fixed at the bottom of the screen instead of pushing content from the top, and reserved a small placeholder space for it from initial render, sized to match its actual height.
Result: down to approximately 0.04.
Step 5: Clean Up the Remaining Small Stuff
The last stretch was smaller wins — a font swap causing a minor reflow on headings (fixed with font-display: swap and matched fallback metrics), and a comment section that briefly collapsed to zero height before its widget script loaded (fixed with a min-height placeholder).
Final result: 0.02 on mobile.
The Full Breakdown
| Step | Fix Applied | CLS After |
|---|---|---|
| Baseline | — | 0.35 |
| 1 | Reserved space for inline ad | 0.19 |
| 2 | Added image dimensions + aspect-ratio | 0.11 |
| 3 | Fixed newsletter bar positioning | 0.04 |
| 4 | Font-display + comment widget placeholder | 0.02 |
What I’d Tell Someone Starting This Same Process
If there’s one lesson I’d pull out of this whole exercise, it’s this: fix the biggest offender first, measure again immediately, and let the data tell you what’s next. I didn’t go in with a rigid plan to fix all five categories evenly — the ad slot alone was worth more than everything else combined, and finding that out early meant I spent my time where it actually mattered instead of spreading effort evenly across problems of wildly different sizes.
I’d also say: don’t chase 0.00. This project landed at 0.02, which is comfortably “good” territory, and further squeezing that number down would have meant diminishing returns for a lot more engineering effort. Perfect is rarely worth what it costs.
Wrapping Up This Series
That’s a wrap on this run of posts — from defining CLS all the way through to fixing a real page, step by step. If you’ve made it through the whole series, you’ve genuinely got everything I use myself on real projects. Go run Lighthouse on your own site, watch the Performance panel for a page load, and see what jumps out. I’d bet it’s one of the things we’ve covered somewhere in this blog.
