CSS & layout

The lh unit sizes to the line, not the font

The lh unit sizes to the line, not the font

Nested a button icon in a paragraph and watched it float half a pixel above the baseline? Bumped up font-size for accessibility and had every ruled-line background lose its grid? These are line-height problems dressed up as font-size problems, and the CSS lh unit is the one that finally names them correctly.

In a new piece titled "You might need to know about the CSS lh unit," Ahmad Shadeed walks through a tour of use cases for lh on ishadeed.com. The value is small. The shift in mindset is bigger than it looks.

What lh actually resolves to

lh is a CSS length unit. It resolves to the computed value of the line-height property on the element it is used on. Not font-size. Not cap-height. The full line box. That distinction is the whole point.

If you write line-height: 1.5 on a font-size: 16px element, 1lh on that element is 24px. Push the font-size to 20px and 1lh becomes 30px. Change the line-height and it moves again. The unit tracks what a line of text actually occupies.

Sizing spacing to the line, not the font

Shadeed opens on the most familiar case:

p {
  margin-bottom: 1lh;
}

One line of clear space between paragraphs, whatever font-size the reader ends up on. The rem you would normally reach for is anchored to the root font, not the paragraph's own line rhythm. lh is anchored to the paragraph itself.

Ruled-paper backgrounds that survive a resize

The pattern that finally sold me on it is the ruled-line background:

.content {
  background-image: linear-gradient(
    to bottom,
    transparent calc(100% - 1px),
    rgba(0, 0, 0, 0.15)
  );
  background-size: 100% 1lh;
}

A one-pixel line sits at the bottom of a tile that is exactly one line-height tall. Repeat it, and the rules land under every line. Tune the type up or down and the rules follow. No hand-picked pixel numbers, no re-tuning per breakpoint.

The mechanism is background-repeat doing its usual work, with the tile height promoted from "some pixel I guessed" to a computed line-box.

Rounding a floated image to a full line

Here's the one that surprised me. Shadeed shows this pattern for a floated image whose height should snap to the nearest whole line, so wrapped text does not end on a half-line orphan:

.content img {
  float: left;
  height: calc-size(auto, round(up, size, 1lh));
}

round() is the piece doing the snapping — round up from the intrinsic size in steps of 1lh. Notice what the syntax names: not "one line of type" as an abstract, but the exact line-height of this element. Change the type and the snap changes with it. Nothing in the CSS mentions pixels.

Fading out a fixed number of lines

For a preview list that stops at line five and fades on the way out:

.list {
  max-height: 5lh;
  mask-image: linear-gradient(
    to bottom,
    #000,
    #000 calc(100% - 1lh),
    transparent 100%
  );
}

Five lines exactly, and the mask's fade covers the last line's worth of height. Bump the font, and both the clip and the fade stretch together. Try to reproduce that with rem and you will always be one media query short of matching.

Icons that live in the same line-box as the label

The button-icon case:

.button {
  --size: 0.8lh;
  svg {
    width: var(--size);
    height: var(--size);
  }
}

0.8 of a line-box. The icon lives inside the same line-box as the label, and asking it to be a fraction of that line-box is closer to what you meant than any fixed em multiple. Change the button's line-height for a denser toolbar and the icon follows.

Two mental shifts worth keeping

First: the sizes that belong to text — margins between paragraphs, background ruling, inline icons, wrapped-image snapping — belong to line-height, not font-size. lh is the unit that finally names that.

Second: the rem-only habit was always a compromise. rem tracks the root font, which is convenient, and wrong at every place where two different type sizes coexist on the same page. lh tracks the actual line box you are in.

Try one substitution on your next component: swap a rem that lives near text for a lh. If the layout stops drifting when you scale type, you have found one of the places lh is quietly the right unit.

Source: ishadeed.com (ishadeed.com)

Related
Browser releases

Safari Technology Preview 246 widens color, images and attr()

WebKit has shipped Safari Technology Preview 246 with a batch of CSS additions — light-dark() taking image values, image(<color>), alpha(), color-mix() with more than two colors, attr() on pseudo-elements, and preview support for font-variant-emoji and word-break: auto-phrase.

June 23, 2026
CSS & layout

The CSS infinity keyword, and what it lets you delete

A tour through Adam Argyle's recipes for the CSS infinity keyword — pill radii, unbounded clamps, and a boolean pattern the cascade can decide on its own.

August 1, 2026
CSS & layout

Route and navigation matching, proposed for CSS

Bramus Van Damme, Noam Rosenthal and David Baron are drafting a CSS spec — css-navigation-1 — that describes URL routes and per-navigation styling in stylesheets, so multi-page View Transitions can drop the pageswap/pagereveal JavaScript.

July 31, 2026