CSS Aspect Ratio Box
Maintain a fixed aspect ratio on any element using the aspect-ratio property.
A CSS aspect ratio box holds a fixed width to height proportion whatever size it ends up being. Give the element aspect-ratio: 16 / 9 and a width, and the browser works out the height. Give it a height instead and it works out the width. It replaces the padding-top hack that dominated responsive embeds for a decade, where a container was padded to a percentage of its own width and the real content was absolutely positioned on top of it.
The property matters most where the size is fluid. A grid cell that is 240px wide on a laptop and 150px on a phone still holds its shape, so a page of thumbnails keeps its rhythm and nothing reflows when images finish loading. The variants below cover a fluid grid of square cells and the padding based fallback, which is still worth knowing because it is what every older codebase is using.
Three fixed ratios
HTML
<div class="ratio-grid">
<div class="ratio-box ratio-16-9">16 / 9</div>
<div class="ratio-box ratio-1-1">1 / 1</div>
<div class="ratio-box ratio-4-3">4 / 3</div>
</div>
CSS
.ratio-grid {
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: center;
}
.ratio-box {
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
color: #0c0c0d;
font-size: .8rem;
font-weight: 600;
}
/* Set a width, the height is calculated from the ratio */
.ratio-16-9 {
aspect-ratio: 16 / 9;
width: 160px;
background: #b8ff57;
}
.ratio-1-1 {
aspect-ratio: 1 / 1;
width: 90px;
background: #c084fc;
}
.ratio-4-3 {
aspect-ratio: 4 / 3;
width: 120px;
background: #38bdf8;
}
Other ways to build it
Fluid grid of square cells
The ratio is most useful when the width is not a number anyone wrote down. Here the grid hands each cell whatever width is left after auto-fill has worked out how many fit, and aspect-ratio: 1 turns that into a height. Resize the window and the cells stay square through every step. The colored blocks below stand in for photographs; put a real <img> inside with object-fit: cover and pictures of any proportion crop to the cell rather than stretching to it.
HTML
<div class="ratio-fluid-grid">
<div class="ratio-cell"><img src="one.jpg" alt=""></div>
<div class="ratio-cell"><img src="two.jpg" alt=""></div>
</div>
CSS
.ratio-fluid-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
gap: .75rem;
}
/* the column width is fluid, so the ratio is what fixes the height */
.ratio-cell {
aspect-ratio: 1;
border-radius: 10px;
overflow: hidden;
}
/* without object-fit the picture stretches to the square
instead of being cropped to it */
.ratio-cell img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
The padding fallback, and how to feature detect it
Percentage padding resolves against the containing block's width, which is the whole trick: padding-top: 56.25% on an empty box gives it a height of 56.25 percent of its width, and that is 16 to 9. The content then has to be lifted onto that padding with absolute positioning, because the padding itself is empty space. The box below is built this way with no aspect-ratio anywhere, so it demonstrates what a browser without the property would show. In real code, wrap it in @supports not (aspect-ratio: 1 / 1) and let everything else take the shorter path.
HTML
<div class="ratio-pad">
<div class="ratio-pad-inner">16 / 9 with no aspect-ratio</div>
</div>
CSS
/* percentage padding resolves against width, so 56.25% is 9/16 */
.ratio-pad {
position: relative;
width: 100%;
height: 0;
padding-top: 56.25%;
border-radius: 10px;
overflow: hidden;
}
/* the padding is empty space, so the content has to be lifted onto it */
.ratio-pad-inner {
position: absolute;
inset: 0;
}
/* everything modern takes the short path instead */
@supports (aspect-ratio: 1 / 1) {
.ratio-pad {
height: auto;
padding-top: 0;
aspect-ratio: 16 / 9;
}
.ratio-pad-inner {
position: static;
}
}
How it works
The aspect-ratio property makes an element maintain a width-to-height ratio automatically. Set a width (fixed, percentage, or auto) and the height adjusts to match the ratio. This replaces the old padding-top hack (padding-top:56.25% for 16:9) with a shorter and readable one-liner.
The value is a ratio, written as two numbers with a slash: 16 / 9, 4 / 3, 1 / 1. A single number is also valid and means that number over one, so aspect-ratio: 2 is the same as 2 / 1. Only one of width and height needs to be set. Set both and the ratio is ignored, because there is nothing left for it to compute.
The ratio applies to the box that box-sizing selects. Under the default content-box, padding and border are added on top of a content area that matches the ratio, so a padded element ends up wider than 16 to 9 overall. Under border-box the ratio describes the outer edge, which is nearly always what a designer means. Most stylesheets set border-box globally, which is why this rarely comes up until it does.
The ratio is a preferred size, not a hard limit. A block element's automatic minimum size stops it shrinking below its content, so a caption two lines longer than expected pushes the box taller and the ratio quietly breaks. overflow: hidden restores it by clipping instead, and min-height: 0 lets the box shrink past its content. Neither is a bug, and the failure mode is a row of cards where one is taller than the rest.
Images bring their own ratio from the file. Setting aspect-ratio on an <img> alongside object-fit: cover overrides that and crops to the box, which is how a mixed set of portrait and landscape photographs is forced into one tidy grid. Without object-fit the picture is stretched to the new proportions instead, and the distortion is obvious on anything with a face in it.
Adding width and height attributes to an <img> in the HTML gives the browser a ratio before the file arrives, which is what reserves the space and stops the page jumping as images load. Modern browsers compute an implicit aspect-ratio from those two attributes, so the attributes and the CSS property solve the same layout shift problem from different ends.
CSS properties used
aspect-ratio- Sets the preferred width to height proportion. Works with one definite dimension, and is ignored when both are set.
object-fit- Controls how a replaced element fills a box whose ratio does not match its own.
covercrops,containletterboxes, the defaultfilldistorts. box-sizing- Decides whether the ratio describes the content box or the border box.
border-boxis what makes a padded ratio box come out the size it looks like it should. overflowhiddenkeeps the ratio when content would otherwise force the box taller than the proportion allows.grid-template-columnsrepeat(auto-fill, minmax(120px, 1fr))gives every cell a fluid width, and the ratio turns that into a height.padding-top- The older technique. A percentage padding resolves against the element's own width, so
56.25%produces a 16 to 9 box with no ratio property involved.
Browser support
| Feature | Chrome | Firefox | Safari | Edge |
|---|---|---|---|---|
object-fit | 32 | 36 | 10 | 79 |
grid | 57 | 52 | 10.1 | 16 |
flexbox | 21 | 28 | 6.1 | 12 |
@supports | 28 | 22 | 9 | 12 |
Can I Use carries no standalone entry for the aspect-ratio property in the dataset this table is generated from, so it is deliberately not listed above rather than filled in from memory. It shipped across the major engines during 2021 and is safe to rely on for anything but a deliberately deep support baseline. Where that baseline matters, feature detect with @supports (aspect-ratio: 1 / 1) and fall back to the padding technique in the second variant, which works everywhere percentage padding does.
Accessibility notes
A ratio box is a layout tool and it changes nothing about the accessibility tree. The risk it introduces is clipping: a box that keeps its proportion while its content grows will hide the overflow, and text that disappears at a large font size or in a different language is a real failure rather than a cosmetic one. Reserve fixed ratios for images, video, and decorative panels rather than for blocks of copy.
Reserving space is the accessibility win here. A page that jumps as images load costs everyone, and it costs most for anyone using a screen magnifier or a switch device, where a target that moves mid tap becomes a misfire. Setting the ratio in CSS, or width and height attributes on the image, keeps the layout still.
Where a ratio box carries a caption, put the caption outside the box rather than inside it. Inside, it competes with the image for a fixed height and it is the first thing clipped when the text wraps to an extra line.
What you can build with it
- Video embeds. A 16 to 9 wrapper around an
<iframe>so a fluid width player keeps its shape without the old absolute positioning dance. - Image grids. Square cells holding photographs of every proportion, cropped with
object-fit: cover. The CSS lightbox uses exactly this for its thumbnails. - Card media areas. The picture at the top of a card holds a 3 to 2 ratio so a row of cards lines up regardless of what each image measures.
- Avatars and logos.
aspect-ratio: 1with a border radius, which stays circular instead of turning into an ellipse when the container is narrow. - Chart and map containers. A plot area that keeps its proportions as the page resizes, so the drawing inside it does not need to be recalculated on every breakpoint.
Mistakes worth avoiding
- Setting both
widthandheight. The two definite sizes win and the ratio is ignored, with no warning anywhere. - Leaving
box-sizingatcontent-boxon a padded ratio box. Padding is added outside the ratio, so the visible box is wider than the proportion asked for. - Assuming the ratio is a hard constraint. Content taller than the box pushes it taller, which is why one card in a row ends up out of line with the rest.
- Using
aspect-ratioon an image withoutobject-fit. The picture stretches to the new proportions rather than cropping to them. - Applying a ratio to a stretched flex item. The item already has a definite cross size from
align-items: stretch, and that size wins.
Frequently asked questions
How do you set an aspect ratio in CSS?
aspect-ratio: 16 / 9 and give the element one definite dimension, usually a width. The browser derives the other one. A single number works too, so aspect-ratio: 1 is a square.Why is my aspect-ratio being ignored?
width and height are set, which leaves nothing for the ratio to compute. The other common cause is content taller than the ratio allows, since the property sets a preferred size rather than a maximum. Add overflow: hidden to keep the shape.What is the padding-top trick and do I still need it?
padding-top: 56.25% on an empty box produces a height that is 56.25 percent of its width, which is 16 to 9. It still works, and it is what you fall back to inside @supports not (aspect-ratio: 1 / 1) when a very old browser matters.Does aspect-ratio work on images?
object-fit: cover so the picture is cropped to the box rather than stretched, which is how a set of mixed portrait and landscape photographs is made to fit one grid.Can aspect ratio boxes stop layout shift?
width and height attributes on the <img> do the same job, because browsers derive an implicit ratio from them.