My question is basically the same as this one, but replace \"line-height\" with \"letter-spacing\": When a relative line-height is inherited, it is not relative to the eleme
CSS variables are not widely supported but would do the trick:
body {
font-size: 18px;
--spacing: 1.2em;
}
.normal-letter-spacing { /* No need to select `.normal-letter-spacing *` */
--spacing: normal;
}
body * {
letter-spacing: var(--spacing);
}
.small {
font-size: 14px;
}
<div>
<p>Lorem ipsum</p>
<p class="small">Lorem ipsum</p>
</div>
<hr />
<div class="normal-letter-spacing">
<p>Lorem ipsum</p>
<p class="small">Lorem ipsum</p>
</div>
They work because the value of a custom property computes to the specified value:
Computed value: specified value with variables substituted (but see prose for "invalid variables")
Therefore, unlike what happens with letter-spacing
, 1.2em
is not transformed to an absolute length.
Then, you can tell all elements to use --spacing
as the value of letter-spacing
. So 1.2em
will be resolved locally with respect of the font size of each element.
Unlike * { letter-spacing: 1.2em; }
, this approach sets --spacing: 1.2em
only once, in the body
, and lets it propagate by inheritance. Therefore, if you want to change that value in a subtree, you only need to override --spacing
in the root. You don't have to select all the subtree.
I would try to use REM over EM to freeze your relation with one value, which would be root (body) font-size. You wouldn't have to care about changes on font-size later.
If you'd like to use rems in more places I would advice to organise all classes in one place so you wouldn't have much problem with maintaining that. It would also be a good idea to keep it as a utility class like
.txt-spacing-big { letter-spacing: 2rem; }
.txt-spacing-medium { letter-spacing: 1rem; }