Units

Choose a unit for a reason, and know which ones respect the reader.

06of 26
≈ 10Min read
10Parts

Absolute and relative

px is absolute: it is the same size whatever surrounds it. Everything else is relative to something — the font size of the element, of the root, of the viewport, or of the parent box. Choosing well means choosing what you want it to follow.

rem and em

the difference
html { font-size: 16px; }     /* 1rem = 16px everywhere */

.card {
  font-size: 1.25rem;         /* 20px */
  padding: 1em;               /* 20px — follows THIS element's font */
  margin-bottom: 1rem;        /* 16px — follows the root */
}
UnitRelative toUse for
remThe root font size — htmlAlmost everything: type scale, spacing, widths.
emThe element's own font sizeSpacing that must scale with the text it belongs to.
em compounds

Nest three elements that each set font-size: 0.9em and the innermost is at 0.73 of the original. That is occasionally what you want and usually a bug. rem never compounds.

Never set the root font size in px

A reader who has set a larger default font in their browser is telling you they need it. html { font-size: 16px } overrides that and freezes the whole page at your size. Leave the root alone, or set it as a percentage.

if you must touch it
/* WRONG: ignores the reader's preference */
html { font-size: 16px; }

/* fine: scales with whatever they chose */
html { font-size: 100%; }

Percentages

A percentage is always relative to something, but what depends on the property, and that catches everyone:

  • width: 50% — half the containing block's width.
  • height: 50% — half the containing block's height, and it only works if that height is known.
  • padding: 5% and margin: 5% — of the containing block's width, even top and bottom.
  • font-size: 120% — of the parent's font size, exactly like em.
  • translate: 50% — of the element's own size, which is what makes the centring trick work.

Viewport units

the family
.hero {
  min-height: 100vh;   /* viewport height */
  width: 100vw;        /* viewport width — includes the scrollbar */
  padding: 2vmin;      /* the smaller of vw and vh */
  font-size: 4vmax;    /* the larger */
}

/* mobile browsers: the toolbar appears and disappears */
.hero-safe {
  min-height: 100svh;  /* smallest — toolbars showing */
  min-height: 100lvh;  /* largest — toolbars hidden */
  min-height: 100dvh;  /* dynamic — follows, and can cause reflow while scrolling */
}
Two traps

100vw includes the scrollbar width, so on a desktop page that scrolls it is wider than the page and causes a horizontal scrollbar — use 100%. And 100vh on a phone is taller than the visible area while the toolbar is showing; 100svh or 100dvh is what you mean.

ch and ex

1ch is the width of the 0 character in the current font. It is the honest unit for line length: max-width: 65ch gives roughly 65 characters per line, which is the range most readable for body text.

a measure that follows the font
.prose p {
  max-width: 68ch;
}

clamp, min and max

These three take the place of most media queries for sizing. clamp(MIN, PREFERRED, MAX) is the one you will use daily: a value that scales with the viewport but never leaves its bounds.

fluid type in one line
h1 {
  font-size: clamp(2rem, 1.2rem + 3vw, 4.5rem);
}

.wrap {
  width: min(1100px, 100% - 3rem);   /* never wider than 1100, always with a gutter */
  margin-inline: auto;
}

.panel {
  padding: max(1rem, 3vw);           /* never tighter than 1rem */
}

Always include a rem term in the middle value of a clamp for font size. clamp(2rem, 5vw, 4rem) with a pure viewport term stops the text scaling when the reader zooms, which is an accessibility failure.

fr, and the sizing keywords

  • fr — a fraction of the free space in a grid. Only valid in grid track sizing.
  • min-content — the narrowest the content can be without overflowing: the longest word.
  • max-content — as wide as the content wants on one line.
  • fit-content — max-content, capped by the space available.
  • auto — "work it out", and what it means depends on the property and the layout mode.

Angles, times and resolution

the rest
transform: rotate(45deg);       /* deg, grad, rad, turn */
transition: opacity 200ms;      /* s, ms */
animation-duration: 0.4s;

@media (min-resolution: 2dppx) { }   /* device pixels per CSS pixel */

A working rule

  • Type and spacing: rem. Consistent, and it respects the reader's font size.
  • Spacing that belongs to the text: em.
  • Line length: ch.
  • Layout widths: %, fr, min() / max() / clamp().
  • Full-screen sections: svh / dvh, not vh.
  • Borders and hairlines: px. A 1px border should be 1px.

Practice