Line-height tricks made simpler with the ‘lh’ CSS unit

With Safari Technology Preview having supported it for a while, and Chromium 109 enabling user-facing support in a first batch of browsers, it's time to see a few ways in which the lh CSS unit is a useful addition.

The lh unit is formally described as follows:

Equal to the computed value of the line-height property of the element on which it is used, converting normal to an absolute length by using only the metrics of the first available font.

When used in the value of the font-size property on the element they refer to, the local font-relative lengths resolve against the computed metrics of the parent element — or against the computed metrics corresponding to the initial values of the font and line-height properties, if the element has no parent. Likewise, when lh or rlh units are used in the value of the line-height property on the element they refer to, they resolve against the computed line-height and font metrics of the parent element — or the computed metrics corresponding to the initial values of the font and line-height properties, if the element has no parent.

Description of the lh unit in the 6.1.1. Font-relative Lengths section of CSS Values and Units Module Level 4 (Editor's Draft).

More concisely, 1lh is the computed line height of:

Uses for the lh unit

Note: The CSS examples below rely on support for the lh unit, which your current browser does not provide. To keep the snippets clearer, I have not included any style fallbacks, so the examples won't look great. Load this article in Safari TP, Chrome 109+, or Edge 109+ to see the effects in action.

Ruled paper effect

The lh unit makes it easy to produce CSS images that are in step with the lines of text. A straightforward example of that is drawing horizontal rules each 1lh, which we achieve here with repeating-linear-gradient().

.index-card {
border: 1px solid;
background-color: gold;
background-image: repeating-linear-gradient(
transparent 0 calc(1lh - 1px),
midnightblue calc(1lh - 1px) 1lh
);
/*
Aligning the background image to the content-box
lets us use any padding on the element.
*/

background-origin: content-box;
padding: 1lh;
}
Emanuel urcă scara întunecoasă. Mirosea în aer a produse farmaceutice și a cauciuc ars. În fundul coridorului îngust, recunoscu ușa albă care îi fusese indicată. Intră fără să mai bată.

This was not impossible to do before. When line-height is a unitless multiplier of the font's size, we can produce a custom CSS property var(--lh) with the same 1lh:

--line-height: 1.5;
--lh: calc(1em * var(--line-height));
line-height: var(--line-height);

This basic technique can be used for a variety of effects, such as Adam Argyle's text of a different color on each line. It's also a good addition to the debugging toolbox. Throughout the article, I'll use the .index-card CSS class on examples to make the line boxes visible.

Nicely sized inline icons

The lh unit is useful for harmonizing sizes with the surrounding text and, in particular, latching onto the line box in a predictable way. This usage is described by Šime Vidas in 2020 (via CSS Tricks):

.with-icon:before {
content: '';
width: 1lh;
height: 1lh;
background: midnightblue;
display: inline-block;
vertical-align: bottom;
margin-inline-end: 0.25em;
}
O ușă se deschise

Here, a pseudo-element of height: 1lh is anchored to either end of the line box using vertical-align: top or bottom to ensure perfect alignment.

Speaking of perfect, I should note that 1lh refers to the ideal line height of an element, but the actual line-height can get bumped by things like inline blocks or <sup> elements:

O ușă1 se deschise

Baseline grid one-liner

I saved the best for last.

Beyond a simple abstraction over calc(1em * var(--line-height)), elements can be made to inherit their parent's line-height. Maintaining vertical rhythm for the entire document is reduced to an elegant declaration:

html {
line-height: 1.6;
}

html * {
line-height: 1lh;
}

How cool is that? I mean sure, there's more to vertical rhythm than an uniform line height. It involves block sizes, along with properties that affect the box model (border, padding, margin). These are currently brewing in the CSS Rhythmic Sizing specification, including a line-height-step property that's already available in Chromium under a run-time feature flag.

The implications of going document-wide for this need to be explored before we can declare we have another * { box-sizing: border-box }-style gold nugget on our hands. In the meantime, it works pretty well applied locally:

.baseline-grid {
line-height: 1.3;
}

.baseline-grid * {
line-height: 1lh;
margin-block: 1lh;
text-indent: 1lh;
}

.baseline-grid .smaller {
font-size: 0.8em;
}

Încăperea în care se găsi părea mai veche încă și mai mucegăită decât coridorul. Lumina venea printr’un singur geam și răspândea o claritate albastră și nesigură peste desordinea din salonaș, unde revistele zăceau răvășite pretutindeni, acoperind masa de marmură și scaunele solemne, învelite în halate albe ca în niște haine comode de voiaj, înainte de mutare.

Emanuel mai mult căzu decât se așeză într’un fotoliu. Observă cu surprindere umbre parcurgând odaia și descoperi subit că geamul din fund era în realitate un aquarium în care pluteau lent pești negri, bulbucați și grași. Câteva secunde rămase cu ochii mari deschiși urmărindu-le alunecarea leneșă, uitând aproape pentru ce venise.

Într’adevăr pentru ce venise aici? Aha! Își aduse aminte și tuși încetișor pentru a-și anunța prezența, dar nimeni nu răspunse.

In this setup, 1lh becomes a fixed unit, like 1rem, that can be used to keep in sync margins, indents, and others.

Conclusion

These have been the three examples I could come up with, or find, in an evening. I hope these can serve as a starting point for finding new, more interesting uses for the lh unit.

The text fragments are from M. Blecher's Inimi cicatrizate (Scarred hearts), available in the public domain.