There are three main options for setting the size of text in the web using CSS. The font size can be set in “pixels”, in “EM”s or in ”REM”s. It can be a little difficult to understand where the differences lie, and which unit of measurement is correct.
Historically, the most common unit for sizing text in the web browser is the pixel. The pixel is very simple to understand and it helps developers and non-technical designers to use a common frame of reference. However, the use of this fixed unit introduces usability problems for many site visitors.
Devices which allow people to browse the web visually have a built-in option to allow the user to increase or decrease the size of the text. In Chrome, for example, I can choose to set the base font size to “large”, which will help me to read longer passages of text more easily and reduce strain on my eyes. Accessibility tools in browsers aren’t just about supporting blind users or handicapped people; they’re for everyone.
If a programmer has set the font size in pixels, the browser follows the rules set in CSS strictly. As an example, the NZZ website uses text set to a fixed size of 20px for articles viewed on larger screens. Because of this choice, the text on this website appears much smaller than on other sites in my browser, because the site doesn’t respect my browser settings for larger text.
The only option I have to increase text size on sites like NZZ is to use the zoom feature on my Mac (Cmd +
) to increase the size of the whole page – including images, separator lines, and so on. For some websites, this works fine, but for others, it can break the layout and even switch the page to the mobile site design.
So, how can I, as a front-end developer, ensure that I support my visitors requirements properly? I can use either REM or EM for text sizing. However, there is an important difference between these two relative (scalable) units.
The EM unit corresponds directly to the size of the parent element in the HTML structure. If the root document size – my body
element – is the equivalent of 20 pixels and I set the size of a paragraph directly “inside” the body
to 1.2em, then the paragraph will be displayed at 24px. If I increase the size of the body
text by 25%, then the paragraph will also increase in size. So I’m supporting my visitors by allowing them to increase the size of the text.
However, if I set sizes across nested elements using EM units, then I’ll run into a problem. Say, for example, that I set the size of a list ul
to 1.1em, so that it’s a little bit bigger than the div
which contains it. The div
‘s font size is the equivalent of 20 pixels, so the ul
is the equivalent of 22px. That’s fine. But what happens if I use another nested UL inside the first ul
? The inner ul
is now 110% of the element it sits in, so it’ll be 24.2px. Another nested ul
(level 2) will be 26.6px. And so on. The deeper the nesting, the bigger the text will get. And because of the nesting, I’ll start to find that the CSS override rules for nested elements will get very complicated, very quickly.
The alternative is to use REM. A REM is a “relative EM”: relative in this case to the html
element, which is the root element of the entire document. Using a base font size on the html
element of 16px will mean that I can easily calculate how large the ul
is in comparison with the HTML element. I want the ul
to be 110% of the base text size, so I’d set the font size of the ul
to 1.1rem. This means that its font size is the equivalent of 17.6px and independent of the parent element.
This example is still based on a pixel value, though. That will re-introduce the usability problem I mentioned. Thankfully, it’s easy to avoid, as there’s only one pixel size defined now: 16px on the html
element. Because the base font size in all modern browsers is 16px, that means I can use a percentage value on the html
element instead: 100%.
If I want all of the text to increase in size for larger screen resolutions, I only have to modify the percentage value on the html
element using a @media
query.
Here’s a simple example of how that might look.
html {font-size: 100%;}
p {font-size: 1rem;}
ul {font-size: 1.1rem;}
@media screen and (min-width: 48em){
html {font-size: 125%;}
}
Addendum: after a comment by Sämi Hauser, I corrected the @media
query in my example to use scalable units too. The breakpoint should also be dependent on the font size set by the visitor in their browser. This will usually be 16px, which makes 48em the equivalent of 768px: the width of a regular iPad screen in vertical format.
This specific detail is a little complex to go into here, but Zell Liew wrote a great article on the subject back in 2016.
Post image: Alexander Andrews @ Unsplash
Leave a Reply