The Ultimate Ideal Bestest Base Font Size That Everyone Is Keeping a Secret, Especially Chet

It’s none.

Clarification

Let me clarify: don’t set a base font size.

body {
  /* font-size: yeah, no */
}

Got a linter or code checker or boss-man hassling you that you need to set something? Ok, use something like this:

html {
  font-size: 100%;
}

Because

Firefox advanced font settings dialog with the size set to 36, minimum to 24, serif font as Georgia, sans-serif as Atkinson Hyperlegible, but still allowing pages to override the fonts.

This approach has the advantage of always inheriting the user’s preferred font size. The one they choose in their browser or on their system. Even if they did not explicitly choose one (because the default was maybe good enough).

All other font sizes (headings, navigation, footer, etc.) should then use relative units. Ideally without being smaller than the default size (with very specific exceptions).

Because you avoid calculation witchcraft, any smaller sizes could be easier for authors to spot — .9rem and 90% are clearly smaller.

Alternatively, font sizes based on viewport units bring risk, not least of which is preventing the user from scaling it large enough to read. Then you need yet more calculation sorcery to prevent it.

Forms

While you’re tearing out an unnecessary base font size declaration, maybe add this to your CSS to honor the user’s preferences in forms as well:

select, textarea, input, button {
  font: inherit;
}

I explain this in more detail in my posts Under-Engineered Text Boxen and Under-Engineered Select Menus.

Print

When it comes to print styles, the text may be too large for your audience (regardless of if or how you set it). If so, you can set the base font in the appropriate point size and all your other relative font sizes will work from that.

@media print {
  body {
    font-size: 8pt;
  }
}

Recap

That’s it. That’s the secret. Don’t set a base font size.

But…

Sure, your case is special. Your case is more important than respecting user choice. I’m not your dad. I can’t stop you. Legally.

Update: 3 April 2024

With Mike Mai’s feedback (linked above) and Scott Kellum’s comments below, I amended the example for when you have to but some style in there. Now it uses html as the selector instead of body.

While this post is about not setting anything, I made the mistake of including something if you were forced to. Folks fixated on that, so that’s on me.

Update: 22 April 2024

Mike Mai wrote The Case for Defining Base Font-size. His argument is that a typeface can warrant setting a base font size. I don’t necessarily disagree. You are imposing a font on users that is potentially too small (or too large), so if you imposed one decision, stacking another is not a stretch.

This assumes the user can download the font (it’s not blocked or interrupted) and the user is ok with the font (and hasn’t blocked it via preferences).

Update: 1 May 2024

My 300 word throwaway post got featured in a video, which I found out about via Spencer Wohlerson the A11y Slack. Also, I had that shirt.

20 Comments

Reply

I’m sorry, this is going to sound like a super basic question. Is setting the base font size to 100% the same as setting it to 1rem? In a series of quick experiments it appears so, but…

Andrew; . Permalink
In response to Andrew. Reply

Yup. Pat also pinged me on Masto, though he was just being mean. This is the challenge of a self-imposed word count.

FWIW, I tend to avoid rem because, from experience, as a unit it has confused the heck out of some devs. But %, and especially 100%, just seems to be easier for many of them to grasp.

Reply

Totally agreed. One additional thing I’ve explored (seems to work) is enabling the native iOS font & size to be the default font-size in Safari. Last I checked, it didn’t scale with user preferences out-of-the-box.

:root{
font-size:100%;
font:-apple-system-body; // iOS reset to user OS preferences
// Any font-family customizations here.
}
@supports (font: -apple-system-body) and (not(-webkit-touch-callout: default)){
// Makes sure desktop Safari doesn't pick up broken iOS issues.
:root{font-size:100%}
}

In response to Chris LaChance. Reply

Chris, I was not aware of this, er, trick. I made a test page (debug mode for easier testing) to see if I could make it happen and yup, my iDevice scales the text with the system accessibility settings.

This is necessary to prime it (note that I do not set a size):

body {
  font: -apple-system-body;
  /* other styles, including font-family */
}

And then that novel @supports declaration:

@supports (font: -apple-system-body) and (not (-webkit-touch-callout: default)) {
  :root {
    font-size: 100%;
  }
}

In the CodePen I use some truly awful fonts to demonstrate I can still set whatever without blowing up this trick.

Reply

uninformed question – but still wondering – How to do this sort of thing in Microsoft Word?

In response to Mary Burk. Reply

Mary, MS Word is well outside the scope of this post. However, features of Word make it easier for people to customize an existing document:

  • styles, which ensure things like headings and lists and plain text and so on are consistent and easy to make larger and smaller; and
  • templates, which a user could use to quickly reformat an entire document into styles that are easier for them to read.
Reply

I’m sure you’re aware of this (or maybe not), but your website scales font sizes up by 30% for paragraph text, which isn’t that different from scaling it on the body:

css
main:not(.home) {
font-size: 130%;
}

Anyway, I don’t really see the issue with setting a custom base font size so long as it’s in relative units (%, em, rem) and not pixels. That way it still scales off the user agent font size. It won’t match the user’s *exact* preferred font size, but at least it will scale proportionally.

Anonymous; . Permalink
In response to Anonymous. Reply

[…] your website scales font sizes up by 30% for paragraph text, which isn’t that different from scaling it on the body

That selector scales it on the content container (so not the home page, not the footer, not the header, not the navigation, etc), which also includes more than paragraph text but less than all text covered by the body. Minor point, of course.

Anyway, I don’t really see the issue with setting a custom base font size so long as it’s in relative units (%, em, rem) and not pixels. That way it still scales off the user agent font size. It won’t match the user’s *exact* preferred font size, but at least it will scale proportionally.

The advice in this brief post is about starting from the user’s own preferences. Ideally authors would not set a base font size without first thinking through why they want to set it. For my site I chose to make it bigger than the user’s default because I wanted to reflect my own loudness. Some users aren’t thrilled by it, of course.

Reply

Is there any reason why you put the font size on body instead of html/:root? I like to put it there (usually 115% or 125%) so I can reference it with rem units elsewhere but I’m wondering if there are any accessibility issues with this.

In response to Scott Kellum. Reply

No accessibility issues, no. Using html/:root is essentially the same for a new page without the burden of pre-existing styles or aggressive design systems. As the very second link in this post notes, where you choose to set it can be a function of the kind of technical debt third-party or unplanned styles will impose.

As far as I know, your approach (referencing the value with rem elsewhere) has no special effect whether you set it there or with the body selector — barring the kinds of opinionated pre-existing or post-development styles I just mentioned.

In response to Adrian Roselli. Reply

Thanks!

A note that setting font size on body vs html/:root does change the way rem behaves. I always recommend people set font size on html so that rem behavior is more consistent. I was curious if there was some accessibility reason to not do this. Again thanks for your response and I’m glad there are no issues with this approach

In response to Scott Kellum. Reply

That is good to know. To spare me building exhaustive test cases, do you have a reference for that nugget? Happy to amend the post if I can confirm it has no wonky unexpected impact.

In response to Adrian Roselli. Reply

Sure thing! A simple test should illustrate this difference in behavior:

Font size on body, you’ll see changing the value has no effect on rem sizes:
https://codepen.io/scottkellum/pen/mdgBxRP

Font size on html, you’ll see that rems now respond to this font-size value:
https://codepen.io/scottkellum/pen/GRLMxrq

Notes:

I’m strongly of the opinion that font size should be defined on html so that proportion to the text size can be more easily maintained throughout a design. This makes creating a built in accessibility interface to select font size or scale components far easier and more resilient.

Counterpoint that others strongly believe: the root font size should always reference the user agent and the user’s set preference for font size.

Why I disagree with this counterpoint: Setting the root font size as a % respects the user’s preference. There is no accessibility detriment to changing the root font size (as long as you use a % value) while also providing a stronger foundation to create additional accessibility features on your website.

In response to Scott Kellum. Reply

Scott, I appreciate the examples. Those are good. I amended the code at the top to use html as the selector.

Of note, though, setting nothing via html nor body and instead setting p { font-size: 2rem; } gets me the same result as your html example, but in a single selector. Granted, if you set that more than once then that benefit is moot. Which makes your point if you want to set something other than the user’s chosen default.

Reply

I’m a fan of the html { font-size: 62.5%; } trick, since modern browsers tend to have a default font size of 16px:

https://codepen.io/adampage/pen/JjVZjBr/?editors=1100

This gives developers — and the visual designers that are often breathing down their necks — the convenience of rem values that closely resemble the px values typically expressed in visual designs, while still affording ultimate control of font size to a browser’s users.

html {
font-size: 62.5%; /* 16px * 62.5% == 10px == 1.0rem */
}

In response to Adam Page. Reply

Sure, it allows (forces) the user to adjust their default browser font size to be 160% just to restore the page to their original and preferred size.

The point of this post is to support users first, not authors.

In response to Adrian Roselli. Reply

Oh, certainly, this technique is just a starting point to make rem values a bit more grokable.

Do still set a sensible, inheritable size on the body element (≥ 16px) along with the usual customizations for heading elements, etc:

https://codepen.io/adampage/pen/JjVZjBr/?editors=1100

Reply

Mike Mai’s argument doesn’t quite hold, either. The font face descriptor size-adjust solves that issue more elegantly. It’s also more resilient as it deals with font loading errors, font swapping glitches, and local font differences across systems.

https://drafts.csswg.org/css-fonts-5/#size-adjust-desc

In response to Yannick Connan. Reply

This is an amazing catch! I would definitely try that out when using custom fonts.

Reply

Now we just need a ultimate ideal bestest base space token (i.e. margin/padding)

Leave a Comment or Response

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>