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.
| class | css | use when |
|---|---|---|
aspect-square | aspect-ratio: 1 / 1 | avatars, profile pics, square icons |
aspect-video | aspect-ratio: 16 / 9 | YouTube/HTML5 video, hero thumbnails |
aspect-[4/3] | aspect-ratio: 4 / 3 | old monitors, slide decks |
aspect-[21/9] | aspect-ratio: 21 / 9 | ultrawide banners |
aspect-auto | aspect-ratio: auto | let 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)
row B — aspect-square + object-contain (fit & letterbox)
row C — custom aspect ratios (arbitrary values)
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.
| class | css | behaviour |
|---|---|---|
object-contain | object-fit: contain | whole image visible, letterboxed (empty space around) |
object-cover | object-fit: cover | fills box, overflow cropped — no empty space |
object-fill | object-fit: fill | stretches to fill — distorts the image |
object-none | object-fit: none | no resize — shows at intrinsic size, cropped to box |
object-scale-down | object-fit: scale-down | like contain or none, whichever is smaller |
| position class | css | use |
|---|---|---|
object-center | object-position: center | default — anchor at center |
object-top | object-position: top | portraits — keep the head, crop the feet |
object-bottom | object-position: bottom | landscape horizons, leg shots |
object-[center_top] | object-position: center top | arbitrary — 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-*)
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).
| family | classes | css property | note |
|---|---|---|---|
| width | w-4 w-1/2 w-full w-screen w-auto w-min w-max w-fit | width | fractions (w-1/2), viewport (w-screen), keywords (w-fit) |
| height | h-4 h-full h-screen h-dvh h-svh h-lvh | height | v4 has dynamic/small/large viewport units (dvh = mobile-friendly) |
| size (v4) | size-4 size-16 size-full size-xs | width + height | shorthand — square elements in one class |
| min-width | min-w-0 min-w-full min-w-min min-w-max min-w-fit | min-width | min-w-0 is the classic flex/grid overflow fix |
| min-height | min-h-0 min-h-full min-h-screen min-h-dvh | min-height | often paired with aspect-* to prevent shrink |
| max-width | max-w-sm max-w-md max-w-prose max-w-screen-xl | max-width | readability caps — see presets below |
| max-height | max-h-64 max-h-screen max-h-full | max-height | clamps tall content (modals, dropdowns) |
max-width presets (readability caps)
| class | width | typical use |
|---|---|---|
max-w-xs | 20rem · 320px | tooltips, small popovers |
max-w-sm | 24rem · 384px | form inputs, narrow cards |
max-w-md | 28rem · 448px | modal dialogs, alerts |
max-w-lg | 32rem · 512px | wide cards |
max-w-xl | 36rem · 576px | blog excerpts |
max-w-2xl | 42rem · 672px | article body (narrow) |
max-w-3xl | 48rem · 768px | article body |
max-w-4xl | 56rem · 896px | wider article body |
max-w-prose | 65ch · ~variable | optimal line length for reading (~65 chars) |
max-w-screen-sm | 40rem · 640px | match the sm: breakpoint |
max-w-screen-md | 48rem · 768px | match md: |
max-w-screen-xl | 80rem · 1280px | match xl: |
max-w-screen-2xl | 96rem · 1536px | match 2xl: |
intent → pattern
| intent | pattern | why |
|---|---|---|
| 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 |