A guide to CSS units — pt. 2: font relative units
Moritz Jacobs
January 29, 2021
If you missed the first part of this article series, start here!
CSS knows many different units to describe dimensions, the spec calls that "lengths". Font relative units of length produce values — as the name states — that are dependent on their parent element's font size. They are multiplicator based values, for example 1.5em == 1.5 × $fontSize There's a few:
em
em is a unit that is relative to the font size of the current element. It is a typographic unit since the age of metal type and was originally a reference to the width of the capital M (hence the name). Examples!
This .box will be rendered with 18px padding because 1em is relative to its implicit font size:
In this next example, all list items will be rendered with a left margin of 3 × 12px = 36px because font-size: 12px; is the closest, inherited font size declaration.
em is easy to understand but can lead to messy and unreadable code due to the nature of font size inheritance and the cascade in CSS. It isn't always clear what font size you are pulling from at any given moment.
That is one of the reasons I prefer…
rem
Like em, rem is relative to font size, but in this case always the font size specified by the root element of the document (:root {…}, for websites it's the html element). So across your whole CSS code base 1rem will always be rendered the same size. But the question is: what size will that be in practice?
To answer that, let's briefly talk about accessibility (a11y for short). Every browser has a default font size and a method for the user to change it.
That's the base font size users will see on your website when unaltered by your CSS. The default default here is 16px and according to this research about 3% of users change this setting, almost always to something bigger than 16. When it comes to the internet, 3% is quite a few million people!
Now if you go ahead and do something like this…
… you break a part of a11y for 3 percent of people. These people rely on text scaling up, and your statically declared font size prevents that.
That doesn't mean all your text has to be >= 16px. It just means people who require bigger text, get bigger text. So if your design uses 14px for body text, an user-set browser font size of 20px (or 125%) will render as 125% × 14px == 17.5px.
To make this work for both your design and your users, just use rem for font sizes and omit setting a baseline font size:
More examples?
Look at these four buttons. They appear identical to 97% of all users (the 16px crowd):
There is no font size context inherited. From left to right:
- uses px for everything
- uses em for font size and px for padding
- uses em for everything
- uses rem for everything
At first sight all of the four implementations seem equivalent. But see what happens when you change the browser's default font size to 24px (150%):
From left to right:
- font-size: 24px This box hasn't changed at all because we override the default setting with a px value. This is bad a11y, the user should be in control of this!
- font-size: 1.5em— better, the font is bigger but padding: 12px is still static, so the padding didn't scale and the designer will probably be unhappy (they tend to get that way).
- padding: 0.5em— the best yet! Now the padding scales as well. 0.5em === 12px because the font size in this box is 1.5em == 24px
- but rem seems to be identical... why bother?
See what happens when these appear in a container with a specified font size that they inherit:
- the first one is still to small
- the second one is way too big and the padding is wrong
- our winner from before is even bigger because the padding adapts
- The one using rem is arguably the "correct" solution, because it scales with the user font size but is not dependent on a parent element's font size declaration.
Conclusion: Use rem units when you're sizing text or when you want something to be proportionate to a user's text size setting. Some people argue that you should use rem for everything. Others disagree. In my opinion, there's no definitive answer for this. It depends on your design, your approach to a11y and your use case. Be aware of the differences and — together with a designer — decide for each of your components how scaling should behave. Be consistent and test things with different font size browser settings and browser zoom levels!
ex, ch
There's two more relative units that you never see in real projects: ex and ch.
ex is relative to the current font's x height. Chris Coyer explains it further:
ch is similar but instead of the font's x-height it relates to the width of the 0 character (pen).
There will be another set of units that are relative to line height, but none of the browsers support them yet: lh and rlh.
See, there's a lot to unpack, once you start to closely look at all of your options. And there's more to come! We will discuss percentage based units in the next part.
Header Photo by Jason Leung on Unsplash
CSS units
relative units
font realtive
rem
em
web typography
Read also
Francesca, Ricarda, 11/21/2024
Top 10 Mistakes to Avoid When Building a Digital Product
MVP development
UX/UI design
product vision
agile process
user engagement
product development
Leonhard, 10/22/2024
Strategies to Quickly Explore a New Codebase
Web App Development
Consulting
Audit
Leonhard, 07/15/2024
User Input Considered Harmful
TypeScript
Web App Development
Best Practices
Full-Stack
Validation