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:
More concisely, 1lh
is the computed line height of:
- the parent when used in
font-size
orline-height
declarations, or - of the element itself in any other declaration.
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.
Note: In Safari TP, zooming in and out of the page affects the computed value of 1lh
inside CSS gradients, causing the ruled paper to shift out of alignment with the text [WebKit#252075].
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;
}
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:
Baseline grid one-liner
Disclaimer / note to future self: A
line-height: <length>;
declaration already inherits just fine without any additional work. Having re-read it, this section needs to be rethought to make a better point, best to ignore it before I have the chance to do that.
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 measure, like 1rem
, that can be used to keep in sync margins, indents, and others.
Note: In Safari TP, imposing a minimum font size via the browser setting affects line-height: 1lh
[WebKit#252108].
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.