Entry 02

Image box that holds any upload

Use it on every image, video or embed whose file you do not control, such as thumbnails, cover photos and avatars. The box keeps its shape whatever the file's ratio, and it has that shape before the file loads.

Open
The four covers are the same shape, whatever the shape of the file: each picture fills its box and is cropped, never stretched. The last one fails to load and shows the box with its background. The avatars are round and the same size beside any length of name, and the pale one still has an edge on the card of its own color.
Code CSS · 17 lines
.thumb {
  inline-size: 100%;
  block-size: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  background-color: var(--surface-muted, oklch(0.9 0 none));
}

.avatar {
  flex: none;
  inline-size: 3.5rem;
  block-size: 3.5rem;
  border-radius: 50%;
  object-fit: cover;
  outline: 1px solid light-dark(oklch(0 0 none / 0.1), oklch(1 0 none / 0.1));
  outline-offset: -1px;
}
Why it works, the rules and the credits 5 reasons · 7 rules · support · credits

Why it works

  1. aspect-ratio works out the height from the width, so the space is there before the file loads.
  2. object-fit: cover scales the picture until it fills the box and crops the rest. The default stretches it.
  3. The background color shows until the image paints, and in its place when the load fails.
  4. An outline with a negative offset draws inside the image's edge. It takes no space and follows the border-radius, so a white avatar on a white card still has an edge.
  5. flex: none stops the text beside the avatar from squeezing it.

Rules

  1. One axis must be auto. A height attribute or a fixed height wins over the ratio. The reset sets height: auto on img, svg and video, and block-size: auto here does the same for an iframe.
  2. object-fit does nothing until the box has both sizes or a ratio.
  3. cover crops. Use contain for logos, product shots and anything that must stay whole. Move the crop with object-position.
  4. Leave the background color off an image that has transparent areas. It shows through them.
  5. A fixed-size image in a flex row needs both sizes, as the avatar has. With only a width it stretches to the height of the row.
  6. In Safari a failed image ignores aspect-ratio and draws a square box. Where a failed load must not move the layout, put the ratio on a wrapper and give the image inline-size: 100% and block-size: 100%.
  7. light-dark() needs the color-scheme from One set of color tokens for light and dark. Without it the outline stays black on a dark page.

Support

aspect-ratio in Chrome 88, Firefox 89, Safari 15. An outline that follows the radius in Chrome 94, Firefox 88, Safari 16.4. light-dark() in Chrome 123, Firefox 120, Safari 17.5. The square box of a failed image is from real Safari 27, tested on 2026-10-01. Chrome 150 keeps the ratio.

Credits

Borrowed from: Ahmad Shadeed, Defensive CSS, the tips Image distortion, Image inner border and Default flexbox stretching. This version draws the inner edge with an outline where his adds an element · Heydon Pickering and Andy Bell, The Frame, Every Layout, which wraps the media. On img, video and iframe the rule goes on the element.

Docs: MDN: aspect-ratio · MDN: object-fit · MDN: outline-offset