responsive units

[check: …]
📖 Pair this live demo with the companion guide (.md) — this page is the rendered ground truth.

1 · unit resolution: px vs em vs rem vs vw

This page pins html { font-size:16px }, so 1 rem == 16px no matter the viewport. em is the trickster: on font-size it means "my parent's font-size", so it compounds down a nested tree. rem ("root em") always jumps straight back to <html>. Every number below is measured live via getComputedStyle.

html (root)   font-size: 16px ← the rem anchor (pinned in <style>)
.em-parent   font-size: 1.25rem (16 × 1.25 = 20)
.em-child   font-size: 2em (parent 20 × 2 = 40)
.em-grand   font-size: 1.5em (parent 40 × 1.5 = 60 — COMPOUNDS)
.rem-sibling   font-size: 2rem (root 16 × 2 = 32 — ignores parent)
unitrelative to2×unit →
pxnothing (absolute)
emparent font-size (here 20px)
remroot <html> font-size
vw1% of viewport width (varies!)
em context = 20px
2px
2em
2rem
2vw

2 · media query vs container query — viewport vs component

A media query (@media) reacts to the viewport — global, so the same component can't look right in a wide sidebar and a narrow main column. A container query (@container) reacts to the component's own box: drag the slider to shrink the host and the card reflows without touching the window.

viewport ≥768px: ? ↑ this flips with the window (try resizing the browser)
520px card: ?

Component card

This card flips horizontal when its container ≥ 400px — regardless of the viewport.

3 · fluid type with clamp()

Skip the breakpoint ladder: clamp(MIN, PREFERRED, MAX) scales a value smoothly between two absolutes. Here the heading is clamp(1rem, 6vw, 2.5rem) — never below 16px, never above 40px, and fluid in between. Resize the window and watch the measured px glide.

Fluid heading — clamp(1rem, 6vw, 2.5rem)

computed font-size
6vw at this viewport
clamped?