Responsive and Accessible font-size
Basics
I assume you already know about basics of px
vs em
& rem
. (If not, you can check them out MDN - CSS units and MDN font-size, as well as a lot of other units like ex
, ch
).
Sidenote - em
vs %
From a quick search and basic testing, em
and %
practically does the same thing - both set based on the parent size, both can be inherited. With the only different being 1em === 100%
. But generally, when using font-size
, em
is used more often - likely just a common coding style preference.
Browser rules
The rule of browser font-size is also very straightforward
- only the root font-size is controlled by the browser/OS settings.. Which means if use any value that is not inherited & relative to the root, it won’t scale.
- All browsers have
16px
as the root font size. This “root” is even above<html>
, and CSS cannot change it. rem
is based on the font size of<html>
. Not<body>
, not any other special tag.
The Responsive and Accessible needs
Some users may have vision needs, or display equipments needs to have larger or smaller font-size than general users.
All OS’s and browsers have this feature built in. For example, you can visit chrome://settings/appearance and see the “Font size” dropdown. You can find this in every browser and OS settings. This made testing also very easy for developers. You can simply toggle the settings and check how your site behaves.
The goal is simple - when the font size setting changes, your web page should scale up/down the font size.
Implementation
First rule: Just don’t use px (at least for font-size)
px
doesn’t scale. So no matter what the user set the browser/OS font size to be, your web pages will always be the “perfect” 12px you want for the design.
With that said, let’s consider a HTML piece (the numbers are the expected final font size in pixel - likely what you get from a design mock):
<div class="root">
<section>
<p class="title">Hello - 20</p>
<p class="quote">Quote - 14
<b class="large-text">Large - 18</b>
</p>
<p class="author">Author - 14</p>
<p class="price">$99.99 - 14</p>
</section>
</div>
See the HTML and both methods in CodePen below (comment / uncomment CSS to test both methods):
See the Pen responsive font-size: em vs 62.5% by Yangguang Li (@liyangguang) on CodePen.
Method 1 - Everything em
This is a method I used for a long time. I first evaluate the “body font-size” (here, I see 14px
is the most common size), then set the container as the font size, using em
. After that, just set other font sizes using em
. Full CSS code to achieve the font size needs are:
section {
font-size: 0.875em;
}
.title {
font-size: 1.428571em;
font-size: calc(20 / 14 * 1em);
}
.large-text {
font-size: 1.285714em;
font-size: calc(18 / 14 * 1em);
}
It’s short and simple, but the size value is ugly. Most times I just use the closest 1 digit - 1.4em
, 1.3em
. But sometimes, designers may require pixel perfect result. Then I have to use calc()
- which still looks less ideal.
Method 2 - 62.5%
+ rem
62.5%
trick is shared a lot around CSS nerds, and it’s an old trick that just works. The key is, setting the root font-size: 62.5%
, and with the default browser size of 16px
, it’s a nice 10px
. The “nice” part is, then it’s super easy to conver from a 14px
in a design mock to 1.4rem
- no calculate or approximation needed.
There’re a few details I need to note about this method:
- You have to use
rem
, notem
. i.e. you have to base every font size on the html, not any parent relationship. Because once you started to useem
in child tags, it just goes back to the same issue of14/16
above, and losses the nice thing about14px === 1.4rem
. 62.5%
- It uses
%
, but the only reason I can guess is0.0625em
just doesn’t look good. - It’s
62.5
. But I personally feel just using6.25
is fine, and maybe better -14px === 14rem
. The only reason I can guess is14rem
means “14 times the font size of the root”, which sounds ridiculous, but “1.4 times” sounds more reasonable. Tho, I might just go with6.25%
.
html {
font-size: 6.25%; /* 1rem => 1px */
}
section {
font-size: 14rem;
padding: 1em;
}
.title {
font-size: 20rem;
}
.large-text {
font-size: 18rem;
}
Yeah, that’s it. I think I’ll start to use this method in my future projects.