ESC

Type to search the knowledge base.

object-fit and aspect-ratio

Crop and scale media with object-fit, lock boxes with aspect-ratio, and stop layout shift when images load.

beginner3 min read
  • css
  • object-fit
  • aspect-ratio

Images and videos arrive with intrinsic dimensions that rarely match the UI slot. object-fit controls how the replaced content paints inside its box; aspect-ratio gives that box a stable shape before the bytes arrive so layout doesn’t jump.

Docs: MDN object-fit, object-position, aspect-ratio.

object-fit values

.thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover; /* fill box, crop overflow */
  object-position: center;
}
Value Behavior
fill Default — stretch to box (distorts)
contain Fit entire image inside; letterbox possible
cover Fill box; crop overflow
none Intrinsic size
scale-down Like none or contain, whichever is smaller
.logo {
  width: 8rem;
  height: 3rem;
  object-fit: contain;
  object-position: left center;
}

.avatar {
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  object-fit: cover;
}

object-fit only applies when the element has a definite box — set both dimensions or one dimension + aspect-ratio/height from layout.

aspect-ratio

.video-wrap {
  aspect-ratio: 16 / 9;
}

.video-wrap iframe,
.video-wrap video {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover; /* for video poster frames / media */
}

.card__media {
  aspect-ratio: 4 / 3;
  overflow: hidden;
}

.card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

Prefer aspect-ratio over the old padding-top percentage hack.

HTML attributes still matter

<img
  src="/hero.avif"
  width="1200"
  height="675"
  alt="Team at the whiteboard"
  decoding="async"
/>

width/height attributes (or CSS aspect-ratio) give the browser an aspect hint for CLS. CSS aspect-ratio on the element is the modern styling approach; attributes remain a good default for content images.

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
  gap: 0.5rem;
}

.gallery figure {
  margin: 0;
  aspect-ratio: 1;
}

.gallery img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

Interview out-loud

“object-fit: cover fills the box and crops; contain shows the whole image. object-position picks the crop anchor. aspect-ratio reserves the box shape to reduce layout shift. I set a real box size, then fit the media inside — fit doesn’t invent height alone without other constraints.”

Footguns

  1. Applying object-fit without height — nothing to fit into.
  2. Distortion from default fill on non-matching ratios.
  3. Cropping faces with cover + object-position: center — tune position.
  4. Ignoring art direction — sometimes <picture> is better than CSS crop.
  5. Fixed height + aspect-ratio conflicts — know which wins in the used size calculation.

Video embed wrapper

<div class="video">
  <iframe
    src="https://www.youtube-nocookie.com/embed/…"
    title="Conference talk"
    loading="lazy"
    allowfullscreen
  ></iframe>
</div>
.video {
  aspect-ratio: 16 / 9;
  position: relative;
  background: #000;
}
.video iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

This pattern reserves space (CLS) and scales cleanly. Same idea for background videos with object-fit: cover on a <video> element filling the box.

Portrait crops for avatars

.avatar {
  aspect-ratio: 1;
  width: 3rem;
  object-fit: cover;
  object-position: center 20%; /* bias toward faces */
  border-radius: 50%;
}

Background-size comparison

background-size: cover|contain is the background-image cousin of object-fit. Prefer content images when you need alt text; use backgrounds for decorative fills. Do not put meaningful photos only in CSS backgrounds — you lose the accessibility path that img + alt provides. When both appear in a design system, document which component uses which so teams do not mix metaphors.

Further reading

Related guides