CSS aspect-ratio and object-fit, With a Focal Point Picker

Two properties solve most picture sizing problems. aspect-ratio: 16 / 9 makes a box keep that shape at any width, replacing the old padding-top hack. object-fit decides how an img or video fills that box: cover crops, contain letterboxes, fill stretches. object-position picks which part stays visible when cover crops.

Quick reference
GoalCSSTailwind
Square boxaspect-ratio: 1aspect-square
Video shapeaspect-ratio: 16 / 9aspect-video
Any ratioaspect-ratio: 4 / 3aspect-4/3 or aspect-[4/3]
Fill and cropobject-fit: coverobject-cover
Show it allobject-fit: containobject-contain
Keep the topobject-position: topobject-top

Updated

Below, one test picture sits in a box you can reshape. Switch between the five object-fit values, click the picture to move the focal point, and copy the CSS or Tailwind classes. Further down: the padding hack next to aspect-ratio, responsive video embeds and card grids with even thumbnails.

object-fit values at a glance

Values and Tailwind classes
ValueTailwind
fillobject-fill
containobject-contain
coverobject-cover
noneobject-none
scale-downobject-scale-down

aspect-ratio next to the padding hack

Before aspect-ratio, a box got its shape from padding-top as a percentage, because vertical padding percentages are measured against the width. It works, but the content has to be absolutely positioned inside. Both boxes below are 16:9.

Old and new, same result

56.25% is 9 divided by 16. The modern version needs one line and lets content flow normally.

<style>
  .old { position: relative; padding-top: 56.25%; background: #fde68a }
  .old > div { position: absolute; inset: 0; display: grid; place-items: center }
  .new { aspect-ratio: 16 / 9; background: #bfdbfe; display: grid; place-items: center }
  .wrap { display: grid; grid-template-columns: 1fr 1fr; gap: 10px }
</style>
<div class="wrap">
  <div class="old"><div>padding-top: 56.25%</div></div>
  <div class="new">aspect-ratio: 16 / 9</div>
</div>

All five object-fit values on the same photo

The picture is 3:2 and every box is square, so each value has a mismatch to deal with and the differences show clearly.

object-fit values
ValueWhat happensTailwind
fillStretches the image to the box. The default for img and video. Distorts when the ratios differ.object-fill
containScales the whole image to fit inside the box. Leaves empty bands (letterboxing) when the ratios differ.object-contain
coverScales the image to fill the box and crops the overflow. No distortion, no bands, some of the picture is cut.object-cover
noneKeeps the image at its natural size and crops whatever does not fit. Good for showing a detail at 1:1.object-none
scale-downActs like none or contain, whichever gives the smaller result. Never enlarges a small image.object-scale-down

fill, contain, cover, none, scale-down

The same 300 by 200 picture in five 110 pixel squares. Watch the red dot: it is the subject cover must not lose.

<style>
  .row { display: flex; flex-wrap: wrap; gap: 8px; font: 12px system-ui }
  .row img { width: 110px; height: 110px; background: #f1f5f9; outline: 1px solid #94a3b8 }
</style>
<div class="row">
  <figure><img src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22300%22%20height%3D%22200%22%20viewBox%3D%220%200%20300%20200%22%20preserveAspectRatio%3D%22none%22%3E%3Crect%20width%3D%22300%22%20height%3D%22200%22%20fill%3D%22%23bfdbfe%22%2F%3E%3Ccircle%20cx%3D%22250%22%20cy%3D%2245%22%20r%3D%2222%22%20fill%3D%22%23fbbf24%22%2F%3E%3Cpath%20d%3D%22M0%20150%20Q70%2095%20150%20140%20T300%20125%20V200%20H0Z%22%20fill%3D%22%2322c55e%22%2F%3E%3Cpath%20d%3D%22M0%20175%20Q90%20140%20190%20172%20T300%20165%20V200%20H0Z%22%20fill%3D%22%2315803d%22%2F%3E%3Ccircle%20cx%3D%2285%22%20cy%3D%22128%22%20r%3D%2216%22%20fill%3D%22%23dc2626%22%2F%3E%3Crect%20x%3D%222%22%20y%3D%222%22%20width%3D%22296%22%20height%3D%22196%22%20fill%3D%22none%22%20stroke%3D%22%231e3a8a%22%20stroke-width%3D%224%22%2F%3E%3C%2Fsvg%3E" alt="Test landscape" width="300" height="200" style="object-fit: fill"><figcaption>fill</figcaption></figure>
  <figure><img src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22300%22%20height%3D%22200%22%20viewBox%3D%220%200%20300%20200%22%20preserveAspectRatio%3D%22none%22%3E%3Crect%20width%3D%22300%22%20height%3D%22200%22%20fill%3D%22%23bfdbfe%22%2F%3E%3Ccircle%20cx%3D%22250%22%20cy%3D%2245%22%20r%3D%2222%22%20fill%3D%22%23fbbf24%22%2F%3E%3Cpath%20d%3D%22M0%20150%20Q70%2095%20150%20140%20T300%20125%20V200%20H0Z%22%20fill%3D%22%2322c55e%22%2F%3E%3Cpath%20d%3D%22M0%20175%20Q90%20140%20190%20172%20T300%20165%20V200%20H0Z%22%20fill%3D%22%2315803d%22%2F%3E%3Ccircle%20cx%3D%2285%22%20cy%3D%22128%22%20r%3D%2216%22%20fill%3D%22%23dc2626%22%2F%3E%3Crect%20x%3D%222%22%20y%3D%222%22%20width%3D%22296%22%20height%3D%22196%22%20fill%3D%22none%22%20stroke%3D%22%231e3a8a%22%20stroke-width%3D%224%22%2F%3E%3C%2Fsvg%3E" alt="Test landscape" width="300" height="200" style="object-fit: contain"><figcaption>contain</figcaption></figure>
  <figure><img src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22300%22%20height%3D%22200%22%20viewBox%3D%220%200%20300%20200%22%20preserveAspectRatio%3D%22none%22%3E%3Crect%20width%3D%22300%22%20height%3D%22200%22%20fill%3D%22%23bfdbfe%22%2F%3E%3Ccircle%20cx%3D%22250%22%20cy%3D%2245%22%20r%3D%2222%22%20fill%3D%22%23fbbf24%22%2F%3E%3Cpath%20d%3D%22M0%20150%20Q70%2095%20150%20140%20T300%20125%20V200%20H0Z%22%20fill%3D%22%2322c55e%22%2F%3E%3Cpath%20d%3D%22M0%20175%20Q90%20140%20190%20172%20T300%20165%20V200%20H0Z%22%20fill%3D%22%2315803d%22%2F%3E%3Ccircle%20cx%3D%2285%22%20cy%3D%22128%22%20r%3D%2216%22%20fill%3D%22%23dc2626%22%2F%3E%3Crect%20x%3D%222%22%20y%3D%222%22%20width%3D%22296%22%20height%3D%22196%22%20fill%3D%22none%22%20stroke%3D%22%231e3a8a%22%20stroke-width%3D%224%22%2F%3E%3C%2Fsvg%3E" alt="Test landscape" width="300" height="200" style="object-fit: cover"><figcaption>cover</figcaption></figure>
  <figure><img src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22300%22%20height%3D%22200%22%20viewBox%3D%220%200%20300%20200%22%20preserveAspectRatio%3D%22none%22%3E%3Crect%20width%3D%22300%22%20height%3D%22200%22%20fill%3D%22%23bfdbfe%22%2F%3E%3Ccircle%20cx%3D%22250%22%20cy%3D%2245%22%20r%3D%2222%22%20fill%3D%22%23fbbf24%22%2F%3E%3Cpath%20d%3D%22M0%20150%20Q70%2095%20150%20140%20T300%20125%20V200%20H0Z%22%20fill%3D%22%2322c55e%22%2F%3E%3Cpath%20d%3D%22M0%20175%20Q90%20140%20190%20172%20T300%20165%20V200%20H0Z%22%20fill%3D%22%2315803d%22%2F%3E%3Ccircle%20cx%3D%2285%22%20cy%3D%22128%22%20r%3D%2216%22%20fill%3D%22%23dc2626%22%2F%3E%3Crect%20x%3D%222%22%20y%3D%222%22%20width%3D%22296%22%20height%3D%22196%22%20fill%3D%22none%22%20stroke%3D%22%231e3a8a%22%20stroke-width%3D%224%22%2F%3E%3C%2Fsvg%3E" alt="Test landscape" width="300" height="200" style="object-fit: none"><figcaption>none</figcaption></figure>
  <figure><img src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22300%22%20height%3D%22200%22%20viewBox%3D%220%200%20300%20200%22%20preserveAspectRatio%3D%22none%22%3E%3Crect%20width%3D%22300%22%20height%3D%22200%22%20fill%3D%22%23bfdbfe%22%2F%3E%3Ccircle%20cx%3D%22250%22%20cy%3D%2245%22%20r%3D%2222%22%20fill%3D%22%23fbbf24%22%2F%3E%3Cpath%20d%3D%22M0%20150%20Q70%2095%20150%20140%20T300%20125%20V200%20H0Z%22%20fill%3D%22%2322c55e%22%2F%3E%3Cpath%20d%3D%22M0%20175%20Q90%20140%20190%20172%20T300%20165%20V200%20H0Z%22%20fill%3D%22%2315803d%22%2F%3E%3Ccircle%20cx%3D%2285%22%20cy%3D%22128%22%20r%3D%2216%22%20fill%3D%22%23dc2626%22%2F%3E%3Crect%20x%3D%222%22%20y%3D%222%22%20width%3D%22296%22%20height%3D%22196%22%20fill%3D%22none%22%20stroke%3D%22%231e3a8a%22%20stroke-width%3D%224%22%2F%3E%3C%2Fsvg%3E" alt="Test landscape" width="300" height="200" style="object-fit: scale-down"><figcaption>scale-down</figcaption></figure>
</div>

Responsive video and embeds

A YouTube-style iframe that keeps 16:9

Give the iframe width 100% and an aspect-ratio. No wrapper div and no absolute positioning needed.

<iframe
  src="https://www.youtube-nocookie.com/embed/VIDEO_ID"
  title="Product walkthrough"
  style="width: 100%; aspect-ratio: 16 / 9; border: 0"
  loading="lazy"
  allow="accelerometer; encrypted-media; picture-in-picture"
  allowfullscreen></iframe>

<!-- A native video can crop to a vertical shape too -->
<video src="/clip.mp4" style="width: 100%; aspect-ratio: 9 / 16; object-fit: cover" muted playsinline controls></video>

Card grids with even thumbnails

Every thumbnail the same shape

Uploads come in all shapes. aspect-ratio plus object-fit: cover makes the grid tidy without editing a single file.

<style>
  .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 10px; font: 13px system-ui }
  .card { border: 1px solid #e2e8f0; border-radius: 10px; overflow: hidden }
  .card img { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; object-position: 28% 64% }
  .card p { margin: 6px 8px }
</style>
<div class="grid">
  <div class="card"><img src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22300%22%20height%3D%22200%22%20viewBox%3D%220%200%20300%20200%22%20preserveAspectRatio%3D%22none%22%3E%3Crect%20width%3D%22300%22%20height%3D%22200%22%20fill%3D%22%23bfdbfe%22%2F%3E%3Ccircle%20cx%3D%22250%22%20cy%3D%2245%22%20r%3D%2222%22%20fill%3D%22%23fbbf24%22%2F%3E%3Cpath%20d%3D%22M0%20150%20Q70%2095%20150%20140%20T300%20125%20V200%20H0Z%22%20fill%3D%22%2322c55e%22%2F%3E%3Cpath%20d%3D%22M0%20175%20Q90%20140%20190%20172%20T300%20165%20V200%20H0Z%22%20fill%3D%22%2315803d%22%2F%3E%3Ccircle%20cx%3D%2285%22%20cy%3D%22128%22%20r%3D%2216%22%20fill%3D%22%23dc2626%22%2F%3E%3Crect%20x%3D%222%22%20y%3D%222%22%20width%3D%22296%22%20height%3D%22196%22%20fill%3D%22none%22%20stroke%3D%22%231e3a8a%22%20stroke-width%3D%224%22%2F%3E%3C%2Fsvg%3E" alt="Test landscape" width="300" height="200"><p>Hill walk</p></div>
  <div class="card"><img src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22300%22%20height%3D%22200%22%20viewBox%3D%220%200%20300%20200%22%20preserveAspectRatio%3D%22none%22%3E%3Crect%20width%3D%22300%22%20height%3D%22200%22%20fill%3D%22%23bfdbfe%22%2F%3E%3Ccircle%20cx%3D%22250%22%20cy%3D%2245%22%20r%3D%2222%22%20fill%3D%22%23fbbf24%22%2F%3E%3Cpath%20d%3D%22M0%20150%20Q70%2095%20150%20140%20T300%20125%20V200%20H0Z%22%20fill%3D%22%2322c55e%22%2F%3E%3Cpath%20d%3D%22M0%20175%20Q90%20140%20190%20172%20T300%20165%20V200%20H0Z%22%20fill%3D%22%2315803d%22%2F%3E%3Ccircle%20cx%3D%2285%22%20cy%3D%22128%22%20r%3D%2216%22%20fill%3D%22%23dc2626%22%2F%3E%3Crect%20x%3D%222%22%20y%3D%222%22%20width%3D%22296%22%20height%3D%22196%22%20fill%3D%22none%22%20stroke%3D%22%231e3a8a%22%20stroke-width%3D%224%22%2F%3E%3C%2Fsvg%3E" alt="Test landscape" width="300" height="200"><p>Lake loop</p></div>
  <div class="card"><img src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22300%22%20height%3D%22200%22%20viewBox%3D%220%200%20300%20200%22%20preserveAspectRatio%3D%22none%22%3E%3Crect%20width%3D%22300%22%20height%3D%22200%22%20fill%3D%22%23bfdbfe%22%2F%3E%3Ccircle%20cx%3D%22250%22%20cy%3D%2245%22%20r%3D%2222%22%20fill%3D%22%23fbbf24%22%2F%3E%3Cpath%20d%3D%22M0%20150%20Q70%2095%20150%20140%20T300%20125%20V200%20H0Z%22%20fill%3D%22%2322c55e%22%2F%3E%3Cpath%20d%3D%22M0%20175%20Q90%20140%20190%20172%20T300%20165%20V200%20H0Z%22%20fill%3D%22%2315803d%22%2F%3E%3Ccircle%20cx%3D%2285%22%20cy%3D%22128%22%20r%3D%2216%22%20fill%3D%22%23dc2626%22%2F%3E%3Crect%20x%3D%222%22%20y%3D%222%22%20width%3D%22296%22%20height%3D%22196%22%20fill%3D%22none%22%20stroke%3D%22%231e3a8a%22%20stroke-width%3D%224%22%2F%3E%3C%2Fsvg%3E" alt="Test landscape" width="300" height="200"><p>Ridge path</p></div>
</div>

Tailwind classes for ratio and fit

Tailwind v4 utilities (check v3 docs if you are on an older version)
CSSTailwind
aspect-ratio: 1 / 1aspect-square
aspect-ratio: 16 / 9aspect-video
aspect-ratio: autoaspect-auto
aspect-ratio: 3 / 2aspect-3/2 (v4) or aspect-[3/2]
object-fit: cover / contain / fillobject-cover / object-contain / object-fill
object-fit: none / scale-downobject-none / object-scale-down
object-position: center / top / bottomobject-center / object-top / object-bottom
object-position: 30% 40%object-[30%_40%]

How the browser resolves aspect-ratio

The ratio only kicks in when one dimension is automatic. Set a width and leave height as auto, and the browser computes the height from the ratio. Set both width and height and the ratio is ignored, since there is nothing left to work out.

The value auto 3 / 2 means use the element's natural ratio when it has one, such as a loaded image, and fall back to 3 / 2 before it loads or when it has none. That is exactly how width and height attributes on img behave behind the scenes.

Choosing a focal point

object-position takes the same values as background-position: keywords like top or right, percentages, or lengths. 50% 50% is the default and keeps the centre. A percentage lines up that point of the image with the same point of the box, so 30% 40% keeps the area a third in from the left and a little above the middle.

For a content system, store the focal point per image as two percentages and write it into an inline style. Every crop on the site then keeps the subject in frame, whatever ratio the layout uses.

How it works

  1. Pick a box ratio and an object-fit value. The preview shows exactly what the browser will crop or stretch.
  2. With cover or none selected, click anywhere on the test picture to set object-position to that point.
  3. Copy the generated CSS, or the Tailwind classes that do the same job.
  4. Use the card grid and video recipes below when you build real layouts.

Tips

Frequently asked questions

What is the difference between aspect-ratio and object-fit?

aspect-ratio shapes the box itself, for any element. object-fit only applies to replaced content such as img, video and canvas, and decides how that content is drawn inside its box. You usually use both: aspect-ratio on the image to fix its shape, object-fit: cover so the picture fills it.

Why does object-fit do nothing?

The image box has the same ratio as the picture, so there is nothing to crop or stretch. object-fit only shows a difference once the box has a different shape, for example a fixed height plus width: 100%, or an aspect-ratio that differs from the file.

Do I still need the padding-top hack?

Not for current browsers. aspect-ratio has worked in Chrome, Edge, Firefox and Safari since 2021. Keep the hack only if you must support older browsers, and check caniuse for your audience.

Does object-fit work on background images?

No. For CSS backgrounds the equivalents are background-size: cover or contain, and background-position for the focal point. object-fit is for real img and video elements, which are better for content images because they carry alt text and support srcset.

Can aspect-ratio be used on a div?

Yes. Any element can take it. A div with width: 100% and aspect-ratio: 1 becomes a square that grows with its column, which is handy for map placeholders, avatars and skeleton loaders.

Related: Aspect ratio calculator, HTML images guide, HTML iframe and video, Flexbox and grid cheat sheet, CSS sizing functions.

Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.

More in Guides

We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.

Product

Who It's For

Features

Resources

Company

View Sitemap