p.enthalabs

font-family recommendations — Chris Morgan

Draft: started 2026-05-09 • Tagged[/css](https://chrismorgan.info/css "CSS"), [/opinions](https://chrismorgan.info/opinions "Opinions (that I hold)")

1. _Never_ assume that a named font will work

There are no web-safe fonts; none are available across all major platforms.

Web fonts (`@font-face` and all) are not safe either:

- If not inlined, subresources can fail to load for all kinds of network reasons.

- Font loading is an area of concern for security, so some block it for safety.

- uBlock Origin has a dedicated button for disabling remote fonts.

- I think some browsers’ data-saving modes block fonts from loading.

(And those that don’t, _should_.)

Or the user might have elected not to let websites choose their own fonts.

I’ve been doing that since 2020, and it makes the web _so_ much better.

For me, generic families are the _only_ ones that will work.

One related JS thing: if you ever use `document.fonts.load("1em my-web-font")`,

_remember that it’s fallible:_ the promise it returns may be rejected.

I came across about four things in the six years 2020–2025 that broke for this reason

(and two of them were in 2025).

Now for a couple of consequence of this.

a) _Always_ include `monospace` if you want the text monospaced

I see this forgotten occasionally, since its lack doesn’t affect most people.

Sometimes on pages that were all-monospace for no good reason.

Those times, it honestly made the pages better! But other times it damages things.

As a concrete example, at the time of writing, Adel Faure’s _ASCII might fly?_ artwork

is missing `monospace`, and looks a little like this for me:

(assuming your styles or user agent don’t make it monospaced!)

. . . . _.---._ . . . . . . . . . '-. . . . . . . . . . . . . :.:.:.:.:.\. . . . . __ . . . . . . :.:.:.:.:.:'-.------------_.-'..'-.----------------------- _:.:.:.:.:.:.:\--._____.-'.:.:.:.:.\-.__:::::::::::::::::: .'-.::.::.::.::'-._'-._____::..:.:.:.:'-:-.-..._:.__:.:.:. -.-.\::.:::.::::::::::__::::(._____:.::.:::.::::'-.:=-.. . .-.-.'--.___:.::::.:::::::( '.--._''':.::::::::::::____.- -. -.'---.::::::::::'-. )::::::::::::_.-----'.-.-.- .^.-.-.-.-.-.-. \:::::::____TT_____.______'-.-.::.::.-._. / \::.:^:.:______.^-----/_-_ -_/\-.-/__/\__\::^:.^::.-..:: / \ / \_/-_-_- /\\___/__/\/_/ \__|LL LL|-/ \/ \( ).^ ._\..____/______/LL\___|LL__LL| /___/\ LL|_______( ^ / )__/____|LL LL|LL|L L|LL||LL| |L L||--___/\______\./ \. /\__|____|LL__LL|_________===_______---/\___\LL__LL| / \ ^ ||/\-_-_-\LL||L/____/____/\ /-_-_- /\\ ||______||LL|:/_\/ :/__\_____\___=|L L |L L ||/______/LL\ /_-_-_-/\ .::::|'/ -||||L L/____/\__==_______-|LL||LL| |/______/ \i-i-i-i/_ 7 - - --|L /\____\/\-_-_-_\==_""--""= |LL__LL| |: : : :L| Add in the fallback `monospace` ``` pre { font-family: "jgs", monospace; } ```

I was actually going to write that last point as “always include a generic family”,

but really it’s only `monospace` that it’s _important_ for. Still—

b) Include `serif` or `sans-serif` if you want that kind of fallback font

Although `serif` or `sans-serif` are rarely _important_,

you probably want to include one of them all the same.

`font-family: Arial, sans-serif;``font-family: Times New Roman, serif;` Otherwise, it’ll use the default font, which is _probably_ serif but could be something else altogether.

2. Stop enumerating fonts that the system might have installed

I’ve seen too much of this kind of thing:

`font-family: "Arial", Helvetica, 'Helvetica Neue', Liberation Sans, "Noto Sans", sans-serif;``Google Sans, Roboto, Arial, sans-serif`_Definitely_ ditch Arial: it’s never going to be _better_ than `sans-serif`. Also ditch Roboto: it’s almost never . It doesn’t help. `sans-serif` will resolve to a font no _worse_ than those you named, and quite possibly _better_.

Here’s a _real_ example I just came across (with spaces restored after punctuation, for it was minified):

`font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif` This is _ridiculous_, strictly worse than `font-family: monospace, monospace`. `monospace` will resolve to a font that is _no worse_.

Now I’m not saying there’s _never_ a case for it.

Consider Georgia) and Times New Roman, both serifs from Microsoft’s Core fonts for the Web.

But they have quite different character: Georgia is a good deal wider.

If that’s what you want for stylistic reasons, I will not begrudge you `font-family: Georgia, serif`.

a) Have _at most_ one named, non-web font

This is an exception

Consider Georgia) and Times New Roman, both serifs from Microsoft’s Core fonts for the Web.

But they have quite different character: Georgia is a good deal wider.

If that’s what you want for stylistic reasons, I will not begrudge you `font-family: Georgia, serif`.

modernfontstacks.com is interesting. Their repository describes more about which fonts for which platforms. Interesting ideas, but I reckon it tries to prescribe beyond what is wise, and that a good chunk of the named fonts would be better removed. Also, they’ve _wildly and catastrophically_ mishandled Courier New—looks like their images were made with the macOS Courier.

3. Strongly consider using _only_ a generic family

So perhaps we’ve removed the locally-installed fonts as not useful;

now how about web fonts?

A web font is slower than no web font; and you can run into issues loading them; so we got `font-display`.

But really, instead of messing around with block and swap periods and redrawing and reflowing tradeoffs,

why not just use whatever font the user has?

It won’t be that bad. They might even have chosen fonts themselves.

Consider it.

a) Yes, even for monospace

Historically, `monospace` defaults were _bad_.

This is mostly Microsoft’s fault for using that abomination Courier New#Courier_New),

which was digitised badly and is effectively a 200–250 weight instead of a 400.

Then, Apple introduced Menlo), and people liked it,

so people started putting _that_ in their font stacks,

since the browser makers weren’t updating `monospace`.

And so it went on.

Well, those days have passed. Browser defaults are all better now.

They may not yet be _spectacular_ in all cases, but they’re never _bad_ any more.

So drop the `Menlo, Monaco, Consolas, Bitstream Vera Sans Mono, Courier, Courier New`, and try just leaving `monospace`.

Here’s a _real declaration_ I just came across (with spaces added after punctuation; it was minified):

`font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif` If you ever _deliberately_ put `Courier New` in a font stack, I’m not sure if we can be friends.

b) Actually, write `monospace, monospace`

Ugly bit of browser history which doesn’t seem to be documented in any spec I can find,

but everyone that old remembers.

If you use `font-family: monospace;` (explicitly or implicitly),

`font-size` will _probably_ default to 81.25% instead of 100%.

(Users can change the generic fonts, the base font size, and the base monospace font size.)

If there’s a second family in the list, this doesn’t happen;

so `font-family: my-web-font, monospace;` is fine,

and `font-family: monospace, monospace;` is fine.

Or set the font-size manually, if you prefer.

If you’re using Lightning CSS, it will ruin `monospace, monospace`;

so for my part I’m writing `monospace, m` for now.

This only affects `monospace`. And maybe text that changes the language, but that’s different again.

I’d like to see if we can convince browser-makers to abandon the `monospace` size thing,

and increase it from the probably-13px to probably-16px.

I guess CSSWG would be the venue to suggest it.

4. Don’t use `system-ui` or `ui-*` for content

UI fonts are designed for short UI texts, _not_ longform content.

UI fonts may not support your content language well: macOS is good about it,

but Windows is _not_, and you’ll end up with things like CJK users getting a bad monospaced font.

Sometimes, people have even deliberately chosen ridiculous system UI font—

quite common in some Android circles.

I _presume_`system-ui` will make content look ridiculous too.

w3c/csswg-drafts issue #3658 discusses some of the problems,

concluding that `system-ui` has been extensively abused.

mdn/content issue #41244 finally added a note to MDN discouraging its overuse.

These families have largely been used as a proxy for better default fonts. This is not a good use of them.

I believe `system-ui` was a mistake.

They should have left it at `-apple-system` and had `BlinkMacSystemFont` change to that:

no other platform had a useful equivalent concept at the time (though some do now),

and it was evident from well before the time of standardisation that

almost all use of this stuff was _ab_ use working around the fact that

browsers weren’t updating their poorly-considered, ancient defaults for the existing generic families.

I believe that `ui-serif`, `ui-sans-serif`, `ui-monospace` and _especially_`ui-rounded` was an _entirely stupid_ idea which should still be ripped out.

Especially given that they’re _not expected to map to any font_ on… anything non-Apple.

Being Apple-only, they don’t _need_ to be in the spec.

They can just expose them as fonts with names that just happen to start with `-apple-`.

(What, we’re not doing prefixes any more? This isn’t a prefix, just looks like one.)