aspect ratio & object sizing

[check: …]
📖 Pair this live Tailwind demo with the companion guide (.md) — this page is the rendered ground truth. ↗ Builds on frontend/foundations: box model (width/height/border/padding — aspect-ratio is the missing third dimension: the ratio that links them).

1 · aspect-ratio: width drives height

aspect-ratio tells the browser the shape of the box. The browser then derives the missing dimension: if you set a width and an aspect-ratio, the height is computed for you. No padding-hack, no JS, no fixed pixel heights. This is how you make a responsive 16:9 video frame, a 1:1 avatar, or a 2.39:1 cinema strip that always keeps its proportions.

/* Tailwind class → CSS */ .aspect-square { aspect-ratio: 1 / 1; } /* avatar, icon tile */ .aspect-video { aspect-ratio: 16 / 9; } /* embed, thumbnail */ .aspect-[4/3] { aspect-ratio: 4 / 3; } /* classic monitor */ .aspect-[2.39/1]{ aspect-ratio: 2.39 / 1; } /* anamorphic cinema */ .aspect-[3/1] { aspect-ratio: 3 / 1; } /* banner */
classcssuse when
aspect-squareaspect-ratio: 1 / 1avatars, profile pics, square icons
aspect-videoaspect-ratio: 16 / 9YouTube/HTML5 video, hero thumbnails
aspect-[4/3]aspect-ratio: 4 / 3old monitors, slide decks
aspect-[21/9]aspect-ratio: 21 / 9ultrawide banners
aspect-autoaspect-ratio: autolet the image's intrinsic ratio win (default for <img>)

Killer rule: aspect-ratio only derives a dimension if the other one is not set explicitly. Set both w-64 h-32 and the ratio is ignored — the explicit height wins (it's a "strong hint", not a hard constraint).

2 · gallery: aspect-ratio thumbnails

Each tile below has a fixed width (the grid column) and an aspect-ratio — the height is derived. The image inside uses object-cover to fill the box (crops overflow) or object-contain to fit entirely (letterboxes). Resize the window: the boxes keep their shape, the crop stays consistent.

row A — aspect-video + object-cover (fill & crop)

cover crop 1
16:9 · cover
tall source forced into 16:9
tall src → 16:9
wide source forced into 16:9
wide src → 16:9

row B — aspect-square + object-contain (fit & letterbox)

contain fit 1
1:1 · contain
portrait in square
portrait → sq
landscape in square
landscape → sq
native square
native 1:1

row C — custom aspect ratios (arbitrary values)

4:3
aspect-[4/3] · 1.33:1
2.39:1
aspect-[2.39/1] · cinema
3:1 banner
aspect-[3/1] · banner

aspect-square → — · object-cover → — · size-16 → —

3 · object-fit & object-position

object-fit only applies to replaced elements (img, video, iframe, embed). It decides what happens when the element's intrinsic size doesn't match the box you gave it. object-position chooses where the anchor point is when the image is cropped or has empty space.

classcssbehaviour
object-containobject-fit: containwhole image visible, letterboxed (empty space around)
object-coverobject-fit: coverfills box, overflow cropped — no empty space
object-fillobject-fit: fillstretches to fill — distorts the image
object-noneobject-fit: noneno resize — shows at intrinsic size, cropped to box
object-scale-downobject-fit: scale-downlike contain or none, whichever is smaller
position classcssuse
object-centerobject-position: centerdefault — anchor at center
object-topobject-position: topportraits — keep the head, crop the feet
object-bottomobject-position: bottomlandscape horizons, leg shots
object-[center_top]object-position: center toparbitrary — pixel/keyword mix
object-[25%_75%]object-position: 25% 75%off-center focal point

Object-fit needs a sized box. The img must have a w-*/ h-* (or be inside an aspect-* parent with w-full h-full) for the property to have anything to fit into. A bare <img class="object-cover"> with no size is a no-op.

4 · sizing utilities: w, h, min, max, size

Tailwind v4 ships a size-* shorthand that sets BOTH width and height in one class — no more w-16 h-16, just size-16. This is the modern way to size square elements (icons, avatars, tiles).

size-* shorthand demo (each box = one size-*)

8
size-8
12
size-12
16
size-16
20
size-20
24
size-24
32
size-32

Each box above is square: size-N = w-N h-N. The gold-check below confirms size-16 resolves to a 64px × 64px square (4rem on each axis).

familyclassescss propertynote
widthw-4 w-1/2 w-full w-screen w-auto w-min w-max w-fitwidthfractions (w-1/2), viewport (w-screen), keywords (w-fit)
heighth-4 h-full h-screen h-dvh h-svh h-lvhheightv4 has dynamic/small/large viewport units (dvh = mobile-friendly)
size (v4)size-4 size-16 size-full size-xswidth + heightshorthand — square elements in one class
min-widthmin-w-0 min-w-full min-w-min min-w-max min-w-fitmin-widthmin-w-0 is the classic flex/grid overflow fix
min-heightmin-h-0 min-h-full min-h-screen min-h-dvhmin-heightoften paired with aspect-* to prevent shrink
max-widthmax-w-sm max-w-md max-w-prose max-w-screen-xlmax-widthreadability caps — see presets below
max-heightmax-h-64 max-h-screen max-h-fullmax-heightclamps tall content (modals, dropdowns)

max-width presets (readability caps)

classwidthtypical use
max-w-xs20rem · 320pxtooltips, small popovers
max-w-sm24rem · 384pxform inputs, narrow cards
max-w-md28rem · 448pxmodal dialogs, alerts
max-w-lg32rem · 512pxwide cards
max-w-xl36rem · 576pxblog excerpts
max-w-2xl42rem · 672pxarticle body (narrow)
max-w-3xl48rem · 768pxarticle body
max-w-4xl56rem · 896pxwider article body
max-w-prose65ch · ~variableoptimal line length for reading (~65 chars)
max-w-screen-sm40rem · 640pxmatch the sm: breakpoint
max-w-screen-md48rem · 768pxmatch md:
max-w-screen-xl80rem · 1280pxmatch xl:
max-w-screen-2xl96rem · 1536pxmatch 2xl:

intent → pattern

intentpatternwhy
responsive 16:9 thumbnail <div class="aspect-video"><img class="w-full h-full object-cover"></div> ratio derives height from the column width; cover fills without distortion
square avatar that never distorts class="size-12 rounded-full object-cover" size-* = square; object-cover crops face into the circle
show whole logo, no crop class="size-16 object-contain" contain letterboxes — preserves the entire brand mark
cinema strip (2.39:1) class="aspect-[2.39/1] object-cover" arbitrary ratio — exact anamorphic look
cap article width for reading class="max-w-prose" ~65 characters per line — typographic optimum
image fills but anchored at the head class="h-full w-full object-cover object-top" cover crops, but keeps the top (portraits)
prevent flex child from overflowing class="min-w-0" lets long text truncate instead of forcing the parent wider
full-bleed hero on mobile browsers class="h-dvh" dynamic viewport height — accounts for mobile address-bar show/hide
square icon button class="size-10 grid place-items-center" size-* = square; one class instead of w-10 h-10