* { line-height: calc(1em + 0.5rem); }
Draft: started • Tagged /css, /meta=also
Just in case that title was too huge to really comprehend,
or you’re using a feed reader that improperly mangles the title:
* {
line-height: calc(1em + 0.5rem);
}
I’ve been using this technique for the last few years and it seems pretty good.
Well, actually in my new 2026 website I’ve gone for 0.375em instead of 0.5em, but we’ll get to that.
I think it’s slightly easier to explain and convince with the 0.5 number. Why
You want a gap between lines for readability.
Otherwise you end up with a paragraph like this one
(unless you’re reading in a feed reader that strips styles).
CSS’s design encourages you to set the gap to a multiple of the font size.
This is fine at small sizes, but works badly for headings and other large text:
because in practice, you want it to scale sublinearly, or not at all.
So historically, people have tended to set line-height each time they adjust font-size.
It works, but it’s far too easy to do inconsistently.
When you get to very large text (such as headings),
you want to have a reasonable gap
between the lines.
This technique gets you that.
The gaps don’t need to scale on font-size.
Whereas if you just wrote
line-height: 1.5,
which looked fine at normal sizes,
it becomes too spacious
and you can’t fit much on screen
and it looks ugly for its
rivers of white.
And if you just wrote
line-height: 24px or 1.5rem or such,
it gets all squished up
and you can’t read it because you’re distracted
because it looks so ugly.
How
Unfortunately, you can’t just define it on :root:
the calc(1em + 0.5rem) will only be calculated once, and the computed value inherited.
So instead you have to define it on every element, so it gets calculated on every element:
* {
line-height: calc(1em + 0.5rem);
}
* is sadly not quite enough, because of pseudoelements.
Depending on what you do, you might want to add ::before, ::after, ::marker, ::first-line, ::first-letter, and potentially more.
Comparing the results to old-style declarations
Supposing you have a base font-size of 16px:
| Font size | calc(1em + 0.5rem) computed line-height | calc(1em + 0.375rem) computed line-height |
| Pixels | Factor | Pixels | Factor |
| 16px | 24px | 1.5 | 22px | 1.375 |
|---|
| 18px | 26px | 1.444 | 24px | 1.333 |
|---|
| 20px | 28px | 1.4 | 26px | 1.3 |
|---|
| 22px | 30px | 1.364 | 28px | 1.273 |
|---|
| 24px | 32px | 1.333 | 30px | 1.25 |
|---|
| 26px | 34px | 1.308 | 32px | 1.231 |
|---|
| 28px | 36px | 1.286 | 34px | 1.214 |
|---|
| 30px | 38px | 1.267 | 36px | 1.2 |
|---|
| 32px | 40px | 1.25 | 38px | 1.188 |
|---|
| 34px | 42px | 1.235 | 40px | 1.176 |
|---|
| 36px | 44px | 1.222 | 42px | 1.167 |
|---|
| 38px | 46px | 1.211 | 44px | 1.158 |
|---|
| 40px | 48px | 1.2 | 46px | 1.15 |
|---|
| 42px | 50px | 1.190 | 48px | 1.143 |
|---|
| 44px | 52px | 1.182 | 50px | 1.136 |
|---|
| 46px | 54px | 1.174 | 52px | 1.130 |
|---|
| 48px | 56px | 1.167 | 54px | 1.125 |
|---|
In traditional typesetting terms, calc(1em + 0.5rem) is 8px leading regardless of font size.
I believe 1em, making the leading not scale, is a good choice, but you can adjust that coefficient if you wish.
As for the 0.5rem part, that one’s definitely more subjective.
Normally I go for 0.5rem, this time I decided to go for 0.375rem, which (simplifying) is 6px, 2px less.
Downsides
The main problem is that it has to be set on everything. That makes it harder to override.
In my sample paragraph above, I couldn’t just write <p style=line-height:1>,
I had to apply that to all of its descendents (br and em) too.