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
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.
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.
28 Comments
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…
In response to .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 especially100%
, just seems to be easier for many of them to grasp.
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, 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.
In response to .Small note, playing around with this today. Needs font: -apple-system-body set on :root for REM to work.
In response to .Weird, because I got it to work on my iPad Mini using the
body
selector. It is charging now, so I cannot test variations nor an iPhone.
uninformed question – but still wondering – How to do this sort of thing in Microsoft Word?
In response to .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:
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.
In response to .[…] 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.
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 .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 thebody
selector — barring the kinds of opinionated pre-existing or post-development styles I just mentioned.
In response to .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 .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 .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/mdgBxRPFont size on
html
, you’ll see that rems now respond to this font-size value:
https://codepen.io/scottkellum/pen/GRLMxrqNotes:
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, 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
norbody
and instead settingp { font-size: 2rem; }
gets me the same result as yourhtml
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.
I’m a fan of the
html { font-size: 62.5%; }
trick, since modern browsers tend to have a default font size of16px
: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 thepx
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 .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 .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:
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.
In response to .This is an amazing catch! I would definitely try that out when using custom fonts.
Now we just need a ultimate ideal bestest base space token (i.e. margin/padding)
If setting the root font-size to 62.5% (so that 1rem is equal to 10px) and then setting the body font-size to 1.6rem the math works out the same to respect the browser default font-size set by the user. Good explanation here: https://www.aleksandrhovhannisyan.com/blog/62-5-percent-font-size-trick/
In response to .Hi, Chris! I refer you to the third paragraph under the Because heading. Also the 6th and 9th comments on the post you linked, both by the post author.
In response to .Thanks Adrian! Yes, I read and acknowledge these points you mentioned in your comment and am not disputing them.
My point is that the math still works out to respect the user’s base font size setting (event when it’s not 16px) when both setting the font-size on the root to 62.5% and setting the body font-size to 1.6rems, which is what Aleksandr’s article shows. I do recognize that this may cause conflicts with 3rd party CSS libraries.
I’m not advocating for this technique. I thought it’s worth clarifying for the root 62.5% font-size technique is all.
An edge-case: fingerprinting-averse users may not wish to adjust zoom (or window dimensions, or scroll interval, or a hundred other things) so defaults need to be somewhat prescriptive for them. They make up a small but disproportionately large portion of my site’s audience.
I’m considering two compromises: either override the base font size in my Onion site only (as that’s nearly exclusively used by such readers), or override it globally and rely on users knowing how to turn stylesheets off (they’re progressive enhancements).
Great post, very informative!
Do you think that it is a good idea to do this in more complicated, more graphically-orientated webapps?
I found that sometimes icon sizes and certain layouts rely on text size not being larger or smaller than the base font size. An argument could be made that they are not responsive enough but I can imagine it would take a long time to account for this.
In response to .I think leaning on user preferences is always a good idea. “Graphically-oriented” could mean anything from charts (where you should definitely consider user defaults for visible labels) to content with lots of pics (where images themselves should probably be limited by viewport sizes anyway).
I would tend to agree that a responsive layout should account for this. Otherwise it’s not responsive, it’s relying on pre-defined values that may have no bearing on the user’s preference or settings.
Leave a Comment or Response