albert.walickihire me
← all solutions
css

How to keep the aspect ratio of an image in CSS?

Keep an image's proportions with max-width and height auto, prevent layout shift with width and height attributes, or force a ratio with aspect-ratio.

Set only one dimension and let the other one be auto. This is the usual responsive rule:

img {
  max-width: 100%;
  height: auto;
}

The image shrinks when its container is narrower than the image, and height: auto recalculates the height from the image's own ratio. Use width: 100% instead of max-width if the image should also grow to fill wider containers. Images get distorted when both sizes are fixed and don't match the file, for example width: 300px; height: 300px on a landscape photo.

Always add width and height attributes

<img src="/photos/lake.jpg" alt="A lake at sunrise"
  width="1200" height="800">

Browsers use the two attributes to work out the ratio before the file downloads. They reserve the right amount of space, so the content below doesn't jump when the image appears. That jump is layout shift, and it counts against Cumulative Layout Shift in Core Web Vitals. The numbers only need to have the right ratio, but the file's real pixel size is the easiest choice.

This is also why height: auto matters. Without it, the height attribute keeps the image 800px tall while max-width makes it narrower, and the image gets squashed.

Force a specific ratio

For a grid of cards where every image should be 16:9 whatever the file is, set the ratio and tell the image how to fill it:

.card-image {
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  object-position: center;
}

object-fit: cover fills the box and crops whatever doesn't fit, so the photo keeps its proportions. Without it, the image would stretch to 16:9. object-position picks the part that stays visible. top works well for portraits, so heads don't get cut off, and percentages like 50% 30% give you finer control.

height: auto is there on purpose. aspect-ratio only works when one of the sizes is auto, and the height attribute from the HTML would otherwise win.

A square avatar is the same idea:

.avatar {
  width: 48px;
  height: auto;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: 50%;
}

cover vs contain and fitting images into boxes with a fixed size are covered in how to fit an image into its container.

You don't need the padding-top hack anymore

Before aspect-ratio, the trick was a wrapper with padding-top: 56.25% (9 divided by 16) and an absolutely positioned image inside it. aspect-ratio has worked in all major browsers for years, so you can delete those wrappers. It also works on elements that have no ratio of their own, like an embedded video:

.video iframe {
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
}

Images in flex rows

An image inside a flex row can get stretched even with height: auto. Flex items stretch to the height of the row by default, and they're also allowed to shrink narrower than their width. Turn both off on the image:

.media img {
  align-self: flex-start;
  flex-shrink: 0;
}
more solutions
work with me

Got something that needs building?

Frontend builds, full-stack features in Django, design-system work. Available for work.

See my workGet in touch