css
CSS aspect-ratio vs the padding-bottom Hack
CSS aspect-ratio vs the padding-bottom hack: why the property is ignored when both dimensions are set, why content overrides it, and the ratio percentages.
You put aspect-ratio: 16 / 9 on a div, it comes out the wrong shape, and the first search result tells you to go back to padding-bottom: 56.25%. aspect-ratio is not broken — it is doing exactly what the spec says, which is to set a preferred ratio that three separate rules are allowed to overrule. The padding hack had none of those rules because it wasn’t a ratio at all; it was a percentage that resolved against something else. Here’s the mechanism behind both, the three reasons the modern property gets ignored, and the percentage table you need if you’re still writing the old one.
The percentages below come out of the same arithmetic our aspect ratio calculator does — divide the height term by the width term — and there is a trick at the end for reading them straight off it.
Why the padding hack worked
The hack rests on one sentence in CSS 2.1, in the definition of the padding properties: “The percentage is calculated with respect to the width of the generated box’s containing block, even for padding-top and padding-bottom.”
Percentage padding-top and padding-bottom resolve against width, not height. That is the whole trick. A box with padding-top: 56.25% is 56.25% of its own container’s width tall, regardless of how tall anything is, which is a 16:9 box by accident of how percentages were specified in 1998.
.embed {
position: relative;
width: 100%;
height: 0;
padding-top: 56.25%; /* 9 / 16 */
}
.embed > iframe {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
The height: 0 is mandatory — otherwise the padding is added to whatever the content height already was — and because the content box is zero tall, everything real has to be pulled out of flow with position: absolute. Two structural elements and a magic number for one shape.
Its failure modes follow from that shape:
- You need a positioned child. Anything left in normal flow sits in a zero-height content box and spills out the bottom.
min-heightis impossible. “At least 200px tall, otherwise 16:9” cannot be expressed, because the box’s height is zero and the ratio lives in the padding.- It’s undefined when the container depends on the child. CSS 2.1 says outright: “If the containing block’s width depends on this element, then the resulting layout is undefined in CSS 2.1.” Shrink-to-fit parents, floats and some flex contexts land there.
The ratio percentages
padding-top percentage = height ÷ width, as a percentage.
| Ratio | Padding percentage | Where you see it |
|---|---|---|
| 16:9 | 56.25% | HD video, YouTube embeds |
| 4:3 | 75% | Older video, many slide decks |
| 3:2 | 66.6667% | Most DSLR photos |
| 1:1 | 100% | Square thumbnails, avatars |
| 1200:630 (“1.91:1”) | 52.5% | Open Graph / link previews |
| 4:5 | 125% | Instagram portrait |
| 21:9 | 42.8571% | Ultrawide, cinematic |
| 9:16 | 177.7778% | Reels, Shorts, TikTok |
Anything over 100% is a portrait box, which is the moment the hack starts to look like what it is. The platform-by-platform version of that column is in social media image sizes in 2026.
The property, and what the spec actually promises
aspect-ratio has been Baseline since Safari 15 shipped it on 20 September 2021, joining Chrome and Edge 88 (January 2021) and Firefox 89 (June 2021); it crossed into Baseline widely available in March 2024. There is no support argument left to have.
The grammar is auto || <ratio>, and <ratio> is a number optionally followed by / and a second number that defaults to 1 — so aspect-ratio: 1.5 and aspect-ratio: 3 / 2 are the same declaration. If either number is 0 or infinite the ratio is degenerate and the property behaves as auto.
The section heading in CSS Sizing Level 4 is the part people skip: “Preferred Aspect Ratios.” The property “sets a preferred aspect ratio for the box, which will be used in the calculation of auto sizes and some other layout functions.” Preferred. Auto sizes. Three consequences fall out of those two words.
1. At least one dimension must be auto
Straight from the spec: “A preferred aspect ratio only ever has an effect if at least one of the box’s sizes is automatic. If neither width nor height is an automatic size, it can have no effect on its preferred sizes.”
.card {
width: 400px;
height: 300px;
aspect-ratio: 16 / 9; /* ignored. silently. */
}
No warning, no console message, no fallback — you asked for a 400×300 box and got one. This is the most common cause of “aspect-ratio not working,” and it usually arrives via a component library or a utility class setting the other dimension somewhere you aren’t looking. height: auto is the fix, and it’s worth writing explicitly rather than relying on it being the initial value.
2. Content wins — the box grows instead of clipping
The hack clipped. The property doesn’t. Spec §4.3, Automatic Content-based Minimum Sizes: “In order to avoid unintentional overflow, the automatic minimum size in the ratio-dependent axis of a box with a preferred aspect ratio that is neither a replaced element, nor a scroll container in that axis, is its min-content size capped by its maximum size.”
In English: a square div with three lines of text stays square; the same div with fifteen lines gets taller, because min-height: auto resolved to the content’s min-content size and beat the ratio. The spec gives both escapes:
.square { aspect-ratio: 1 / 1; overflow: auto; } /* scrolls, stays square */
.square { aspect-ratio: 1 / 1; min-height: 0; } /* overflows, stays square */
Making the box a scroll container (auto, hidden or scroll) takes it out of the rule entirely. min-height: 0 keeps the ratio and lets the content spill — the old hack’s behaviour, opted into on purpose. The same automatic minimum applies in the inline axis too, so a fixed-height ratio box can be pushed wider by a long unbreakable child unless you set min-width: 0.
3. Replaced elements come with a ratio of their own
A replaced element that has a natural aspect ratio — img, video, canvas, an object with dimensions — already knows its own shape, and aspect-ratio: auto means “use that one.” Declaring aspect-ratio: 16 / 9 on an <img> overrides that and stretches the picture, because object-fit’s initial value is fill. If you meant “crop to 16:9,” you want both:
img {
width: 100%;
height: auto; /* without this, the natural height wins */
aspect-ratio: 16 / 9;
object-fit: cover; /* crop, don't stretch */
}
There is also a two-value form. With aspect-ratio: 3 / 2 auto, the spec says the specified ratio applies “unless it is a replaced element with a natural aspect ratio, in which case that aspect ratio is used instead” — so an <img> holds 3:2 until the file arrives with a ratio of its own. A placeholder shape for an image whose real dimensions you don’t know yet.
Why <img width height> stops the page jumping
Browsers reserve space for an image before it loads, and the mechanism is this property. The HTML rendering spec says a matching width/height attribute pair is used “as a presentational hint for the ‘aspect-ratio’ property of the form auto w / h.” The auto in front means the attributes only shape the box until the real file arrives with its own ratio.
Because it’s a presentational hint, any author rule outranks it — which is why the reset img { max-width: 100%; height: auto; } is load-bearing. Put a fixed height on images and you have set both dimensions, rule 1 applies, the hint does nothing, and you have inflicted the CLS third of Core Web Vitals on yourself.
<iframe> is the exception. The spec is precise about which elements get the hint: “The width and height attributes map to the aspect-ratio property (using dimension rules) on img and video elements, and input elements with a type attribute in the Image Button state,” plus canvas. embed, iframe and object map their attributes to width and height only. So a YouTube embed’s width="560" height="315" reserves no space at all, which is precisely why “responsive iframe” is still a search people make.
Write the ratio yourself — .embed { aspect-ratio: 16 / 9; width: 100%; } .embed iframe { width: 100%; height: 100%; } — the padding hack’s whole job, in two declarations and no positioning.
The media query that shares the name
@media (min-aspect-ratio: 16/9) is a different feature with the same word in it. Media Queries Level 4 defines it as “the ratio of the value of the width media feature to the value of the height media feature” — the viewport’s shape, not any element’s. It tells you nothing about the box you’re styling.
Ratios compare by division, so “tall” ratios are less than “wide” ones: min-aspect-ratio: 16/9 matches viewports at least that wide-relative-to-tall. It’s a range-type feature, so @media (aspect-ratio >= 16/9) reads better and has been Baseline widely available since September 2025 (Chrome/Edge 104, Firefox 102, Safari 16.4). To size a component by its own width rather than the viewport’s, you want container queries.
”But email”
The padding hack’s last claimed refuge is HTML email, and it’s a narrower refuge than it looks. Can I Email puts aspect-ratio at around 41% support — unsupported across Gmail, Yahoo, AOL and the Windows desktop Outlooks. But the hack needs position: absolute to put anything inside the box, and Yahoo and AOL are documented as supporting relative but not absolute, with the desktop Outlooks supporting neither. Gmail is the one big client where the swap genuinely buys you something.
So: one client’s worth of upside, in a medium where the reliable answer is still fixed-width tables and images with real width attributes.
What to do
- Delete
heightbefore you debug anything else. If both dimensions are set, the ratio is ignored by specification, not by bug. - Decide what happens when the content is too big. Default: the box grows.
overflow: hiddenkeeps the shape and hides the excess;min-height: 0keeps the shape and lets it spill. - On images, pair it with
object-fit: coverand keep thewidth/heightattributes in the HTML for the CLS win. - On iframes, set the ratio in CSS — the attributes do nothing for you there.
- Get the numbers right. The aspect ratio calculator does both directions: type 1920 × 1080 and it reduces to 16:9 by GCD, or pick a preset (16:9, 4:3, 1:1, 9:16, 21:9) or a custom pair and it fills in the missing dimension. For a padding percentage, enter a width of
10000and calculate the height — 16:9 returns 5625, which is your 56.25%.
The Flexbox & Grid playground is the fastest way to see how a ratio box behaves as a grid item (repeat(auto-fill, minmax(12em, 1fr)) plus aspect-ratio: 1 / 1 is the spec’s own square-tiles example), the image resizer has a ratio lock for producing the file at the size you just calculated, the social media image resizer does it once per platform ratio, and the clamp() calculator handles the other axis of responsive sizing — with its own post on the math.
The short version: the padding hack faked a ratio with a percentage and got a hard constraint by accident. aspect-ratio asks for a ratio and gets a preference — which is better behaviour almost always, and surprising exactly once.