Font Smoothing

Put white text on a dark surface and look closely. On a Mac, it comes out a little bolder and a little fuzzier than the same text on white.

DefaultAntialiased
The quick brown fox

MacOS smooths text in browsers by thickening the edges of every glyph, a leftover from the days of subpixel rendering on low resolution screens. On dark backgrounds that extra thickness reads as bloom.

Every demo on this page only changes on a Mac. Windows renders with ClearType and ignores the property, Linux never had it, and iOS Safari does not do subpixel antialiasing at all. If you are reading this anywhere but macOS, nothing below will look any different.

ChangelogFaster cold startsFunctions now boot in under 100ms. No changes are needed on your side.
-webkit-font-smoothing: auto

The property is -webkit-font-smoothing: antialiased. It tells the browser to skip the thickening and use plain grayscale antialiasing, which renders the glyph at its true weight.

Where it shows

The difference is easy to see on dark backgrounds and a bit harder to see on light ones.

AppearancePick a theme, or follow your system and switch to dark at sunset.
AppearancePick a theme, or follow your system and switch to dark at sunset.

That is why this mostly comes up when a product ships a dark mode. Everything looks fine in light mode, then the dark theme arrives and every heading feels half a weight heavier than the design file.

Thin weights

The thickening the default rendering adds is the same for every weight, but it is not felt the same way. A bold heading barely needs it, while a light weight often relies on it: sometimes 300 only looks readable on a dark background because the renderer has been quietly fattening it.

DefaultAntialiased
The quick brown fox jumps over the lazy dog200
The quick brown fox jumps over the lazy dog300
The quick brown fox jumps over the lazy dog400
The quick brown fox jumps over the lazy dog500
The quick brown fox jumps over the lazy dog600
The quick brown fox jumps over the lazy dog700

From 400 up, the antialiased side just looks cleaner. At 300 the text comes out lighter than you meant, and at 200 the strokes start to fall apart. Thin text gets even thinner on a non-Retina screen, where a stroke can be less than a pixel wide. So if you set body text at 300 or below on dark surfaces, give it a look on a 1x display before turning this on everywhere. If you stick to 400 and up, like most products do, you are fine.

The other two values

The property takes four values, and the two nobody reaches for are worth knowing.

ChangelogFaster cold startsFunctions now boot in under 100ms. No changes are needed on your side.

none turns antialiasing off entirely. Edges go hard and stepped, the way type looked before any of this existed. There is no real use for it in a product, but it is the fastest way to see how much work antialiasing is doing.

subpixel-antialiased is the one you might actually want one day. It forces the default back on, which matters because the recommendation below is a global rule on body. Once that is in place you have no way to exempt a region without this value.

Usage

app.tsx
<body class="antialiased">
  <!-- ...and one region that wants the default back -->
  <div class="subpixel-antialiased">...</div>
</body>
body {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/_ Opt a region back into the browser default. _/
.light-panel {
-webkit-font-smoothing: subpixel-antialiased;
-moz-osx-font-smoothing: auto;
}

Both properties are non-standard and only do anything on macOS. Windows, Linux, iOS and Android ignore them, which is fine, because the bloom is a macOS problem. Since Firefox 128, Firefox on macOS treats the WebKit property as its own, so the -moz-osx-font-smoothing line is only there for older versions.

Resources

Search concepts

Search for a command to run...