Here’s a confession: for the longest time, I thought “reserving space” was just a fancy way of saying “use aspect-ratio and call it a day.” Turns out, it’s a whole category of problems on its own, and iframes in particular have a nasty habit of breaking rules that images happily follow. So let’s get into it properly.
Images First — The Easy Case
For a plain <img> tag, the fix is genuinely simple, and I covered the core of it in the last post. But since this is the “reserve space” post specifically, let’s zoom in on the HTML side of things, because I think it gets undersold.
<img src="banner.jpg" width="1200" height="600" alt="Banner">
Just adding those width and height attributes — even without a single line of CSS — tells the browser the image’s intrinsic ratio before the file downloads. Modern browsers use this to compute an aspect ratio automatically. It’s honestly one of the cheapest wins in all of web performance, and I still see it skipped constantly on client sites I audit.
Now, the Annoying Case: Iframes
Iframes are where things get messy, because unlike an <img>, you often don’t control what’s inside them. YouTube embeds, Google Maps, payment widgets, chat plugins — you’re renting space in someone else’s box.
Here’s my go-to approach:
.iframe-wrapper {
aspect-ratio: 16 / 9;
width: 100%;
}
.iframe-wrapper iframe {
width: 100%;
height: 100%;
border: 0;
}
Wrap the iframe, set the ratio on the wrapper, stretch the iframe to fill it. I’ve used this exact pattern on probably a dozen client projects, and it hasn’t failed me yet.
What About Iframes With Unpredictable Height?
This is the part that trips people up. Some embeds — think comment widgets, certain chat tools, or CMS-injected forms — genuinely don’t have a fixed ratio. Their height depends on their content, which you can’t know in advance.
For these, I lean on a rougher but honest technique: estimate a minimum height based on typical content, and accept some shift as a trade-off.
| Embed Type | My Typical Reserved Height | Why |
|---|---|---|
| Video (16:9) | Calculated via aspect-ratio | Fixed, predictable ratio |
| Google Maps | Calculated via aspect-ratio | Fixed, predictable ratio |
| Comment widgets (Disqus, etc.) | 400-600px min-height | Content-dependent, estimate only |
| Chat/support widgets | Fixed via position: fixed | Overlay, doesn’t push content |
| Payment forms (Stripe, etc.) | 300-450px min-height | Varies by payment method shown |
I’m not going to pretend this table is scientific — these numbers come from watching real embeds on real sites over time, not some official spec. But having any reasonable estimate beats having zero reserved space, every single time.
A Technique I Genuinely Like: Skeleton Placeholders
For embeds where height is unpredictable, I’ve started reserving space with a light gray skeleton block that matches my estimated minimum height, then letting the real content replace it once it loads. It doesn’t eliminate shift entirely if my estimate is off, but it drastically reduces both the visual jarring and the actual CLS number, since the shift happens against a placeholder instead of jumping other content around.
Third-Party Scripts: The Sneakiest Offender
I want to call this out specifically because it burned me once on a real project: third-party scripts that inject their own iframe after your page has already rendered — think consent banners, some chat widgets, certain ad networks — don’t care about your carefully planned layout at all. They just show up and shove things around.
My rule of thumb now:
- Reserve space for third-party embeds before the script loads, using a placeholder div with an estimated size
- Load these scripts with
asyncordeferwhere possible, so they don’t block rendering - Test with the actual third-party script active — not a mockup — because vendors change their embed sizes more often than you’d think
Wrapping Up
If I had to sum up this whole post in one sentence, it’d be this: images are a solved problem, iframes are a negotiation. You can’t always control what shows up inside someone else’s embed, but you can absolutely control how much guessing your layout has to do while it waits. Reserve space generously, estimate honestly, and treat every third-party script as a potential layout troublemaker until proven otherwise.
Next time, we’re diving into lazy loading — and how to get the performance benefits without reintroducing the exact shift problems we just fixed.
