In CSS, there are lots of different units that can be used to size elements on a page—px, vw, ch, em, rem, and far too many others to list here. Of all these units, rem happens to be the most reliable for sizing elements responsively, allowing you to scale your UI with the browser's base font size and to respect user preferences for accessibility. Let's understand why rem is the ideal unit for font size and how setting the base font size to 62.5% can make our lives easier while also honoring user preferences.

Skip table of contents

Table of Contents

Don't Use Pixels for Font Size

The traditional unit for sizing anything on the web is the CSS pixel, but it's not ideal for font size. While pixels do make it easy for you to translate mockups from design software directly into CSS, they're an absolute-length unit, which means that one CSS pixel corresponds to a fixed physical pixel size (device pixel) on a user's screen. This may be 1/96th of an inch on 96 DPI devices, or it may be some other physical quantity on a device with a different DPI. For our purposes in this article, the important thing to understand is that while a CSS pixel may not always correspond to the same physical quantity between two devices that have different DPIs, it does refer to a fixed quantity on a single device.

CSS pixels are the easiest unit to understand because they're grounded in physical measurements. But like other absolute units, they don't scale with other measurements. And using pixels for font sizing actually harms accessibility. To understand why, we need to learn about user font size preferences.

Respecting a User's Font Size Preferences

Every browser applies a root font size of 16px to a document, meaning that unstyled body text will have a font size of 16 CSS pixels out of the box. However, both developers and users can change this behavior. Developers can change the font size of the root element (html) with CSS so that all elements inherit that new font size. On the other hand, users can go into their browser's settings (e.g., chrome://settings/fonts in Chrome) and configure their font preferences:

The Chrome settings page for changing one's preferred font size. Two sliders can be seen: one for the font size and another for the minimum font size. Sample sentences are shown below those sliders, along with pickers for the user's preferred font family (which, by default, is Times New Roman).

User preferences for font size should always take precedence over your CSS. This means that using hard-coded pixels for font sizing is inaccessible to users with vision impairments, who may want to scale up the font size of your page so that text is easier to read. When you set a font size in pixels, it will always be rendered at that size, regardless of what font size a user prefers.

Preferred Font Size vs. Browser Zoom Level

Users can also scale a web page using browser zoom settings, in which case pixels are not entirely problematic because the page still scales up proportionally.

The Chrome settings page shows various groups, one of which is labeled page zoom. There's a dropdown input, with a currently selected value of 100%.

For example, changing the base font size from 16px to 18px is equivalent to setting the page zoom to be 112.5%. So you could get away with using pixels for all dimensions and leaving it up to users to zoom in your page if they need to.

However, more commonly, users have a preferred font size for their monitor rather than a preferred zoom percentage—after all, it's much easier for users to reason about pixels than it is some arbitrary percentage zoom. Moreover, as in the example above, percentages may yield floating-point results that don't appear in the browser settings, forcing a user to choose between the two closest values that are available.

This means that we should always respect the user's preferred base font size rather than forcing them to figure out whether we support zooming only, font size scaling only, or both zooming and font size scaling. You can learn more about respecting user font size preferences in WCAG Criterion 1.4.4 Resize Text.

Scaling Font Sizes with rem

So absolute units won't work if we care about honoring a user's font size preferences. Fortunately, CSS also offers relative-length units, which reference other elements on the page rather than always corresponding to a fixed physical quantity. Two such units are em and rem.

When used for a child element's font size, em refers to the parent font size. For example, if an element has a font size of 24px, then 0.5em translates to a font size of 12px for a child element. While in some cases em can be useful for padding and margins, it's problematic for font sizing. If you give an element a font size in em and a child a font size in em, those two ems will create a compounding effect. This makes it less than ideal in component-driven development because an element may be nested arbitrarily deep in other em-sized containers. Thus, an element's font sizing cannot be determined reliably just by looking at its own CSS.

By contrast, rem (which stands for "root em") always references the base font size of the document. Assuming that the base font size is 16px, we get the following values:

  • 1rem = 16px
  • 1.5rem = 24px
  • 0.5rem = 8px

The great thing about rem is that we can safely use it for font sizes in nested layouts and component frameworks since it always references the root font size, rather than some unknown parent element's font size. Thus, it's more predictable than em. This makes rem the ideal unit for sizing elements responsively on a page—you can use it for padding, margins, font sizes, border radii, and even width and height. When users go in and change their base font size preference at the browser level, all rem-based dimensions will scale accordingly.

Unfortunately, if we use rem, we won't have the luxury of translating pixel designs directly into CSS. To render a font size of 12px, for example, we need to do some math to figure out that 12 ÷ 16 = 0.75rem (assuming a base font size of 16px). This is tedious—but we can work around it!

Setting the Base Font Size to 62.5%

It would be nice if we could think in pixels but also reap the benefits of using rems.

Humans are pretty good at thinking in tens since we're familiar with the decimal (base-10) number system. If instead 1rem were equal to 10px, we could easily translate any pixel amount to rems by dividing it by 10. So 12px would be 1.2rem, 24px would be 2.4rem, and so on.

How can we do this? Well, 10 is 62.5% of 16px, the default root font size of your browser. So if we set the base font size of our document to be 62.5%, then 1rem will equal 10px:

html {
  /* 62.5% of 16px base font size is 10px */
  font-size: 62.5%;

.some-element {
  /* 10 * 1.2 = 12px */
  font-size: 1.2rem;

Of course, if we were to just stop here, our base body font size would be illegibly small at a mere 10px. We can fix this by setting the font size of our body to be 1.6rem, which yields an effective font size of 16px for all visible text on the page:

html {
  /* 10px */
  font-size: 62.5%;

body {
  /* 16px */
  font-size: 1.6rem;

At this point, you may be a little suspicious. We scaled the root font size down, but then we scaled it back up for the body—doesn't that defeat the whole purpose of scaling the root font size down in the first place?

The important thing to understand is that the root font size (on the html element) need not be the same as the font size on the body element. In this case, we have a root font size of 10px because we scaled the html font size down to 62.5%, but we did this solely for the convenience of translating pixels into rems. Our body font size—all of the visible text on the page—is still scaled back up to an effective font size of 16px so that it matches the browser's font size.

These are just two ways of looking at the same equation. Originally, we had to perform this calculation to express a target pixel font size in rems:

12px in rems: 12 / 16 = 0.75rem

But here, we can express 12 as a multiple of 10:

12px in rems: (1.2 × 10) / 16 = 0.75rem

We can then group the 10 with the 16 and expand the division:

Grouped:    1.2 × (10 / 16) = 0.75rem
Expanded:   1.2 × 0.625 = 0.75rem

Notice that the right-hand side of the equation is still the same as it was originally, but the left-hand side expresses the target font size conveniently as a multiple of 10. This is just a more formal way of arriving at the same result that we derived intuitively.

The 62.5% trick makes it easier to reason about pixels as relative units; the alternative is to perform mental calculations, rely on preprocessor math, or use CSS's calc utility.

Is This Accessible?

So far, we've only considered the case where the browser has an unchanged root font size of 16px. But what if a user changes their browser's font settings?

Well, recall that the body font size is 1.6rem. And that means that we really have this equation:

html font size = 62.5% of browser font size
body font size = 0.625 × 1.6rem = 1 (i.e., 100% of the browser font size)

Notice that we really don't care what the browser font size happens to be. Since 1.6 and 0.625 are inverses of each other, they cancel out in this equation, yielding the browser's font size. No matter what root font size a user picks, the CSS will always respect it.

Example: A User Prefers Larger Font Sizes

Let's look at an example. Assume that we have this CSS:

html {
  font-size: 62.5%;
body {
  font-size: 1.6rem;
h1 {
  font-size: 4.8rem;

Now, suppose a user goes into their browser settings and sets their preferred base font size to be 20px. Does this create any problems for us? Let's see how the math pans out for body text:

Browser font size:  20px
html font size:     0.625 × 20px = 12.5px
body font size:     1.6rem = 1.6 × 12.5px = 20px

So the body font size equals the browser font size, as expected.

What about the 4.8rem-sized heading? After the user sets their base font size to 20px, this heading will have an effective font size of 60px:

Heading font size = 12.5px × 4.8rem = 60px

This may seem strange since we actually wanted 4.8rem to equal 48px, but remember: That's only true when we assume a base font size of 16px, which isn't the case here. If a user increases their preferred base font size, all font sizes will scale up proportionally (when using rems). So in this case, it's good that the heading font size is 60px because it means that the ratio between the h1's size and the browser font size was preserved:

Before: 48px ÷ 16px = 3
After:  60px ÷ 20px = 3

Final Thoughts

Using a base font size of 62.5%, together with rems for font sizing, provides the ideal compromise between respecting user font size preferences and making it easier to translate pixel measurements into responsive units. Everyone wins!


The photo used in this post's social media preview was taken by Chrissie Giannakoudi (Unsplash).


Post comment

This comment system is powered by the GitHub Issues API. You can learn more about how I built it or post a comment over on GitHub, and it'll show up below once you reload this page.