Using aspect-ratio for Responsive Media and Preventing Layout Shift
Media that loads after the page renders is the classic cause of cumulative layout shift: the browser does not know how tall an image or video will be until its dimensions arrive, so content below it jumps when the box suddenly grows. The CSS aspect-ratio property fixes this by reserving the correct height from a known width and a declared ratio, before a single byte of the media loads. This guide covers aspect-ratio for responsive images, video, and embeds, and the padding-top hack fallback for older engines. It is part of Intrinsic Sizing Techniques within Mastering Container Queries & Responsive Layouts.
Why a CSS ratio instead of fixed heights or JavaScript
The problem is precisely timing: layout happens before media dimensions are known. A fixed pixel height appears to solve it but breaks responsiveness — the media is locked to one height regardless of width, so it letterboxes or distorts as the column changes size. Reading the image's natural size in JavaScript and setting a height after load is worse, because that runs after the first layout, which is the exact moment the shift you wanted to prevent has already happened.
aspect-ratio resolves the timing problem inside CSS. Given a width — from a column, a grid track, or 100% of a parent — and a ratio, the engine computes the height during the first layout pass, so the box is the right size before the media arrives. When the media loads it pours into a box that already fits, and nothing below it moves. This is both a Core Web Vitals win (CLS approaches zero) and a correctness win, and it costs no script and no measurement.
There is an accessibility dimension as well. Reserving space keeps the page geometrically stable while assistive technology and keyboard focus traverse it; a user tabbing through a page does not have content reflow out from under them as images stream in. The ratio also respects zoom, because it is a pure proportion applied to whatever the zoomed width resolves to.
Complete working implementation
The block below handles the three media cases — an image, a video element, and an iframe embed — each kept at a stable ratio with no layout shift, plus a @supports fallback to the padding hack for engines without the property.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body { font-family: system-ui, sans-serif; margin: 2rem; max-width: 40rem; }
/* Reserve a 16:9 box from the width before media loads.
object-fit: cover crops to fill without distortion. */
.media-16x9 {
aspect-ratio: 16 / 9;
width: 100%;
object-fit: cover;
display: block;
background: #7aa2ff14; /* visible placeholder while loading */
border-radius: 0.5rem;
}
/* iframes have no object-fit; the ratio alone shapes the box */
iframe.media-16x9 { border: 0; }
/* Fallback for engines without aspect-ratio: padding-hack wrapper.
padding-top: 56.25% == 9/16, reserving height as a % of width. */
@supports not (aspect-ratio: 16 / 9) {
.ratio-fallback {
position: relative;
width: 100%;
padding-top: 56.25%;
}
.ratio-fallback > * {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
}
</style>
</head>
<body>
<h2>Image</h2>
<!-- width/height attributes give browsers a default ratio too -->
<img class="media-16x9" width="1600" height="900" alt="Scenic ridge at dawn"
src="https://example.com/ridge.jpg">
<h2>Video</h2>
<div class="ratio-fallback">
<video class="media-16x9" controls poster="https://example.com/poster.jpg">
<source src="https://example.com/clip.mp4" type="video/mp4">
</video>
</div>
<h2>Embed</h2>
<div class="ratio-fallback">
<iframe class="media-16x9" title="Location map"
src="https://example.com/map" loading="lazy"></iframe>
</div>
</body>
</html>
In the modern path the wrapper <div class="ratio-fallback"> is inert — the inner element sizes itself via aspect-ratio. Only when the property is unsupported does the @supports not rule activate the absolute-positioned fill.
Key technique: ratio plus a definite width
aspect-ratio only reserves space when the box has a definite size on one axis to compute the other from. For block media that means giving the element width: 100% (or a track width) so the height resolves from the ratio. The property is aspect-ratio: <width> / <height>, an unitless proportion, so 16 / 9, 4 / 3, and 1 / 1 all work. If the content has a natural size that conflicts, aspect-ratio yields to it unless you also constrain the conflicting axis — which is why width: 100% on the media (or object-fit: cover for raster images) is part of the recipe rather than optional.
Variation: a dark-mode placeholder that shifts nothing
While media streams in, the reserved box can show a theme-aware placeholder so the layout reads as intentional rather than blank, and it still never shifts. This pairs naturally with prefers-color-scheme.
.media-16x9 {
aspect-ratio: 16 / 9;
width: 100%;
object-fit: cover;
background: #eef1f8; /* light placeholder */
}
@media (prefers-color-scheme: dark) {
.media-16x9 { background: #1c2230; } /* dark placeholder, same box */
}
Because the box dimensions come from the ratio, changing the placeholder color is purely cosmetic and cannot reintroduce layout shift.
Browser support note
aspect-ratio is supported in Chrome 88+, Edge 88+, Safari 15+, and Firefox 89+, so it is reliable on every engine shipped since 2021. Browsers also derive a default ratio from an <img> element's width and height attributes (Chrome 79+, Firefox 71+, Safari 14+), which reserves space even with no CSS. For anything older, the @supports not (aspect-ratio: 16 / 9) block falls back to the padding-top percentage hack.
FAQ
How does aspect-ratio prevent cumulative layout shift? It reserves the correct box height from the ratio and the known width before the media loads, so when the image or video arrives it fills the existing box instead of pushing surrounding content down.
Do I still need width and height attributes on images?
Keep them. Modern browsers derive a default aspect-ratio from the width and height attributes automatically, which reserves space even without a CSS rule. The CSS aspect-ratio property is for elements without those attributes, like videos and iframes.
What is the padding-hack fallback for aspect-ratio?
Wrap the media in a container with padding-top set to the ratio as a percentage of width, and position the media absolutely to fill it. It reserves height the same way, for engines that predate the aspect-ratio property.
Does aspect-ratio work on iframes and video embeds?
Yes. aspect-ratio applies to any element with a definite width, including iframe and video. It is the cleanest way to make a YouTube or map embed responsive without the padding wrapper.
Related
- Intrinsic Sizing Techniques — the parent guide for content-driven box sizing.
- min-content, max-content, fit-content() Explained — sizing boxes from their content rather than a ratio.
- Fluid Typography Without JavaScript — another technique for eliminating layout shift.
- Building Responsive Cards with Container Queries — cards whose media keeps a stable ratio across sizes.
- Optimizing CSS Animations for 60fps — cross-area: keeping rendering stable and shift-free under motion.
Related articles
More pages in the same section.