zachleat’s Ugly Mug

Zach Leatherman

Laissez-faire Font Smoothing and Anti-aliasing

25 May 2017 Read this in about 7 minutes.

Recently, Twitter made a global anti-aliasing CSS change to their website. Before writing this post, I didn’t know very much about anti-aliasing—so I decided to learn everything I could about it to better understand the reasoning behind a decision like that. Here’s what I learned.

Controlling anti-aliasing modes in CSS is easy. A little too easy Tin foil hat. There are two non-standardized, implemented vendor-prefixed properties to control anti-aliasing on text: -webkit-font-smoothing and -moz-osx-font-smoothing. The full browser support matrix is available under font-smoothon Can I Use. But before we dive in, let’s level set on what the values for these properties are:

  • Disabled:
    • -webkit-font-smoothing: none
    • In my tests, Firefox had no mechanism to disable font smoothing 👍
  • Grayscale anti-aliasing (also known as Full pixel or Traditional anti-aliasing)
    • -webkit-font-smoothing: antialiased;
    • -moz-osx-font-smoothing: grayscale;
  • Subpixel anti-aliasing
    • -webkit-font-smoothing: subpixel-antialiased
  • Let the browser decide (Uses subpixel anti-aliasing when available; this is the default)
    • -webkit-font-smoothing: auto
    • -moz-osx-font-smoothing: auto

Try it out on this page


What’s the difference between these modes?

To get a closer look, I strapped a cheap 25x macro lens to my smartphone and took some pictures. They’re pretty distorted around the edges because of the lens, but they’re good enough to see what’s going on.

When you zoom in on the image, you can see the individual pixels—each with their own red, green, and blue lights! Fascinating!

Compare the three different modes below. These photos were taken of 24px text using the Times typeface displayed on an LG UM95 Ultra Widescreen monitor (109dpi, a low DPI makes it easier to see).

Anti-aliasing is disabled.
Grayscale or full pixel anti-aliasing.
Subpixel anti-aliasing.
Anti-aliasing is disabled. Note that the pixel is either on or off. Not partially illuminated.
Grayscale or full pixel anti-aliasing. Note that the highlighted pixel is partially illuminated (with each red, green, and blue light illuminated the same amount).
Subpixel anti-aliasing. Note that in the highlighted pixel, the red and green lights are illuminated but the blue is not.

Remember that hexadecimal color values have 2 hex digits for red, 2 digits for green, and 2 digits for blue? Note that when those values are all the same (#eeeeee, #222222, or #666666), the color is a shade of gray. The same principle applies for the pixels in grayscale anti-aliasing. When each red, green, and blue light are illuminated the same, the pixel appears to be gray.

Subpixel anti-aliasing uses a similar technique, but with the full RGB color pallette. Making a pixel red means that only the left third of the pixel will be illuminated, which gives us additional rendering precision.

While subpixel anti-aliasing is considered to be state of the art, hardware advancements are rendering (͡° ͜ʖ ͡°) it unnecessary. On HDPi or retina screens, subpixel anti-aliasing is increasingly unnecessary to render an accurate portrayal of a glyph. The more pixels you have to work with, the more effective grayscale anti-aliasing is. That’s why it’s unlikely that iOS will ever support subpixel anti-aliasing, saving them the work of supporting the font-smooth property.

Apple’s iPhone 6 (326dpi), showing horizontal stripe pixel geometry, RedGreenBlue, and grayscale anti-aliasing. Note that this display also uses “Dual Domain” pixels, which are skewed at alternating angles.

But not all screens share the same horizontal stripe pixel geometry. Here’s a Google Pixel smartphone, using a diamond subpixel shape called PenTile (trademarked by Samsung). As the picture shows, PenTile clearly does support subpixel anti-aliasing, but does not support controlling it with the -webkit-font-smoothing property. A diamond configuration is likely to handle subpixel rendering in different orientations better than a horizontal stripe could.

Google’s Pixel (441dpi), showing PenTile pixel geometry (a diamond shape) with subpixel anti-aliasing.

So, Twitter made a change

Recently switched their website to force grayscale anti-aliasing on HiDPI screens:

@media screen and (-webkit-min-device-pixel-ratio: 2), screen and (min-resolution: 2dppx) {
	body {
		-moz-osx-font-smoothing: grayscale;
		-webkit-font-smoothing: antialiased;

Asthetically as we’ve seen, using grayscale anti-aliasing makes things appear lighter and thinner. It’s usually employed to lighten text or icons that are placed on dark backgrounds, almost as a shortcut to avoid loading an additional (but perhaps more appropriate) Light or Hairline web font. It is unusual to apply this change to a site globally but from a technical perspective it is consistent with iOS’ preference for grayscale anti-aliasing. Perhaps it would clash with Android’s embrace of subpixel anti-aliasing if -webkit-font-smoothing were supported there.

To see more big players in the font-smooth game, check out the Microsoft Edge CSS Usage list. Related: does some weird stuff.


Taking a “smoke ’em if you got ’em” approach to subpixel anti-aliasing feels warranted here. It seems silly to opt-out of a technically superior subpixel approach if it’s supported on the user’s platform and browser.

Platforms that support subpixel rendering may or may not support font-smooth to control it—Android is a prime example of this. After reading issues on web browser bug trackers, it almost seems like the browsers that did implement this now regret doing so. But independent of font-smooth support, subpixel anti-aliasing is not going away any time soon—even if iOS holds out forever.

The safe bet here is to defer to browser and platform defaults and only use font-smooth overrides sparingly and as a last resort.


Retweet to share this post