Sizing the legible letter

Yes, it’s true. This is a blog entry about sizing text for the web.

…look, I know you’re still out there. I can hear you breathing.

Sure, sizing text isn’t the most glamorous topic. What’s more, it can get downright contentious, with camps forming around their favorite units of measurement. The truth is, each approach has its own unique strengths and limitations. So below, let’s dive into a few popular methods, discuss them with a bit of equanimity, and wrap up this little essay with a better understanding of our options for font-size.

Right, then! A spirited yet hopefully even-handed discussion of font-size awaits! Onward!

Our old friend, the pixel

Let’s dive in with a quick little demo. To start us off, I pulled a short passage from an old, favorite book, marked it up in some basic HTML5, and applied some light CSS. If you’d like, you can view my little page.

Now, sharp-eyed reader that you are, you’ve probably noticed the markup’s as modest as the design:

<article>
	<header>
		<h1 class="main-title">
			<img src="dorothy.png" alt="" />
			A Brief Excerpt from <cite>The Wonderful Wizard of&nbsp;Oz</cite>
		</h1>
		<h2 class="byline">by <a class="person" href="#">L. Frank Baum</a></h2>
	</header>

	<div class="article-body">
		<p><b class="caps">The Lion hesitated</b> no longer, but drank till…</p>
		…
	</div><!-- /end .article-body -->

	<footer>
		<p>Words by …</p>
	</footer>
</article>

Our page is essentially one big article element, which contains:

  1. A header to house the headline (h1.main-title) and byline (marked up oh-so-imaginatively as h2.byline).
  2. The primary text is contained inside a div with a class of article-body.
  3. Finally, a footer element rounds out the copy with some attribution.

Nothing too fancy, right? Well, the styling’s just as unassuming. Now, since this is an article about font sizing, let’s not worry our pretty little heads about layout. Instead, let’s focus on the fonts:

body {
	font: normal 16px/24px adobe-text-pro, Cambria, Georgia, "Times New Roman", Times, serif;
}
.main-title {
	font: normal 30px/36px abril-display, Palatino, Georgia, Times, serif;
}
.main-title cite {
	font-size: 42px;
	line-height: 50px;
}
.article-body {
	font-size: 18px;
}
.caps,
figure,
footer {
	font-size: 14px;
}

From the outset, it’s obvious the page relies heavily on Adobe Text Pro set on the body, with TypeTogether’s elegant (and new!) Abril Display prettying up our .main-title headline. And with those defaults established, the rest of the CSS is dedicated to specifying a few different font sizes: five rules, five different font-size values, each set in pixels. And that’s basically it.

Easy, right? I think that’s half the appeal of the mighty pixel, actually: just how easy it is to use. We can transfer a few pixel values from Photoshop into CSS, and—voilà—your work’s nearly finished. But efficiency aside, I think there’s something appealing about the promise of control that comes with declaring a few quick pixel values, a control that’s so darn appealing to us designers. But for all its strengths, px isn’t the only game in town.

In fact, there’s one well-known drawback to sizing type in pixels: Internet Explorer’s “Text Size” tool (still) won’t resize any text set in pixels. Now, it’s true that many desktop browsers, including more recent versions of IE, include some form of page zoom, which can magnify the size of your entire design, including its text.

Before I start sounding like a crazy person who hates page zoom, I should mention that exploring alternatives to the venerable pixel might result in some real, practical benefits. Ever built a menu that allowed the user to dynamically change the size of text on a page? I’ve worked on a few, including one that launched recently. If your design’s universally set in pixels, each text size “level” would require you to redeclare sizes for every px-based element of your design. So it’s very possible that on some projects, pixels simply won’t scale. (Pun unfortunate, but intended.)

Now that I’ve stepped off my soapbox, let’s take a look at a slightly more proportional alternative, a unit of measurement that does play nicely with resizing: namely, the em.

Becoming context-aware with ems

Because I’m a sucker for nostalgia, let’s revisit our body rule. Here’s what we’re currently working with:

body {
	font: normal 16px adobe-text-pro, Cambria, Georgia, "Times New Roman", Times, serif;
}

Before we start getting more proportional, let’s tweak it ever so slightly:

body {
	font: normal 100% adobe-text-pro, Cambria, Georgia, "Times New Roman", Times, serif;
}

Catch the difference? All we’ve done is change the font-size value to 100%, setting our document’s base type size to the browser’s default, which is usually 16px. As a result, we’re left with a flexible baseline, a point of reference from which we can size our text up or down using relative units of measurement—specifically, the em.

It’s worth mentioning that some folks prefer setting the body to a font-size of 62.5%, as this gives us a relative baseline of approximately 10px—which can make relative font sizing much, much easier. Richard Rutter, author of the original 62.5% technique, wrote a fantastic article for A List Apart recommending 100% as a better baseline, one that ensured more consistent cross-browser results.

But I digress. Regardless of what your baseline preference might be, our job at this point is to convert our pixel-based font-size values into their em equivalents. To do so, we’ll need to do a teensy bit of math: we’ll simply take the target pixel value we’ve already set, and then divide it by the font-size of its containing element—in other words, its context. The result is our desired font-size, but converted neatly into relative terms, which we can then drop directly into our CSS as ems.

In other words, relative font sizes can be calculated thusly:

target ÷ context = result

Let’s take a quick example. (And I promise to never say “thusly” again.) So: remember our main headline?

.main-title {
	font: normal 30px/36px abril-display, Palatino, Georgia, Times, serif;
}

In order to turn the headline’s 30px size into an em-based value, we need to define it in relationship to its context—that is, the font-size of the body element. Let’s assume our font-size: 100% is roughly equivalent to 16px. So let’s plug our .main-title’s target font size (30px) and its context (16px) into our formula:

30 ÷ 16 = 1.875

Boom. 30px is 1.875 times greater than 16px, so our font size is 1.875em.

Now you may recall that the book’s title was wrapped in a cite element inside our main headline, and sized a bit larger than the text that preceded it:

.main-title cite {
	font-size: 42px;
}

If we want to convert that 42px to ems, it’s important to note that our context has changed. Since we’ve set a font-size on our .main-title headline, the font-size of any elements within need to be expressed in relation to that value. In other words, our @cite@’s target value of 42px needs to be divided not by 16px, the @body@’s font-size, but by the 30px we set on our headline:

42 ÷ 30 = 1.4

And that’s it. With a little bit of contextual awareness, we’re left with a proportional font-size for our .main-title headline, as well as the cite inside it:

.main-title {
	font: normal 1.875em/36px abril-display, Palatino, Georgia, Times, serif;	/* 30 / 18 */
}
.main-title cite {
	font-size: 1.4em;				/* 42 / 30 */
	line-height: 50px;
}

(I personally like including the target and context values as comments in my CSS, usually off to the right of the relevant property. I’ve found it makes revising these relative values much easier, especially since the origin of a value like 1.875em might not be immediately apparent. But hey, that’s just my own especial brand of obsessiveness.)

Sizing text proportionally simply requires a little contextual awareness. And that applies to setting our document's line-height, too. For example:

.main-title {
	font: normal 1.875em/36px abril-display, Palatino, Georgia, Times, serif;	/* 30 / 18 */
}
.main-title cite {
	font-size: 1.4em;				/* 42 / 30 */
	line-height: 50px;
}

The leading in both rules—36px for .main-title, and 50px for the cite within it—are still in pixels, which means the line-height values won’t scale along with their respective relative font-size values. Presumably because they hate freedom.

But thankfully, we can quickly move those pixel-based values into something more proportional. But this time, our context is the font-size itself, our target the pixel-based line-heights. So with that in mind, let's do a little bit more math:

36 ÷ 30 = 1.2

50 ÷ 42 = 1.2

There we are: both .main-title and the cite within it have a line-height of 1.2. And since the two elements share the same leading, we can actually just set the value once on the higher element, and let its descendants inherit it:

.main-title {
	font: normal 1.875em/1.2 abril-display, Palatino, Georgia, Times, serif;	/* 30 / 18; 36 / 30 */
}
.main-title cite {
	font-size: 1.4em;				/* 42 / 30 */
}

That is, as the kids say, that. What’s more, we don't actually need to add units to the line-height, as Eric Meyer’s covered so ably before. Instead, we can leave that proportional value in place, sans pixels, percentages, or ems.

But yes! Context rocks! And armed with that knowledge, we can turn to our remaining pixel-based rules:

.article-body {
	font-size: 18px;
}
.caps,
figure,
footer {
	font-size: 14px;
}

As before, with some simple math and an awareness of a given element’s context, we can turn those values into oh-so-flexible ems:

.article-body {
	font-size: 1.125em;			/* 18 / 16 */
}
/* figure and .caps are children of .article-body, so their context is 18px */
figure,
.caps {
	font-size: 0.777777778em;		/* 14 / 18 */
}
/* The footer's context is the body element, so we'll use 16px here */
footer {
	font-size: 0.875em;			/* 14 / 16 */
}

And with that, we’ve successfully moved our page beyond the pixel. The design’s identical to the original px-based version, but considerably more flexible, proportional, and accessible.

Meet the rem

The em is powerful voodoo indeed, but it’s not without its limitation. Obviously, it requires an awareness of an element’s context, which can be unwieldy at best. What’s more, it can complicate moving modules within your design, as their font-size might be tied to a specific position in the document’s hierarchy. So for especially complicated, content-heavy sites, this could potentially require some work.

Thankfully, there’s been some traction on improving our old friend the em. Introduced in the CSS3 specification, the rem behaves much like the em: it’s a relative unit of measurement, sizing text up or down from a baseline value. But the rem is sized relative to the root of your document—in other words, the value set on the body element.

Here’s what our CSS looks like, once we switch everything over to rems:

body {
	font: normal 100%/1.5 adobe-text-pro, Cambria, Georgia, "Times New Roman", Times, serif;
}
.main-title {
	font: normal 1.875rem abril-display, Palatino, Georgia, Times, serif;		/* 30 / 16 */
}
.main-title cite {
	font-size: 2.625rem;		/* 42 / 16 */
}
.article-body {
	font-size: 1.125rem;		/* 18 / 16 */
}
.caps,
figure,
footer {
	font-size: 0.875rem;		/* 14 / 16 */
}

This is still relative font sizing, so we’re still using our target ÷ context formula. But now, our context is 16px throughout the CSS. That’s right: no more tracking various context values, worrying about which element’s inheriting which font-size value and going slowly mad. And as someone who hates math, this consistency is kind of exciting.

Sadly, support for the rem is still evolving. Firefox 3.6+, Chrome, Safari 5, and IE9 all support the rem. (And IE9+ even resizes text set in rems!) Unfortunately, while support’s broad, that doesn’t mean it’s universal. So if you’re supporting a significant number of browsers beyond that list, you might need to declare a fallback in pixels:

body {
	font: normal 100% adobe-text-pro, Cambria, Georgia, "Times New Roman", Times, serif;
}
.main-title {
	font: normal 30px abril-display, Palatino, Georgia, Times, serif;
	font-size: 1.875rem;		/* 30 / 16 */
}
.main-title cite {
	font-size: 42px;
	font-size: 2.625rem;		/* 42 / 16 */
}
.article-body {
	font-size: 18px;
	font-size: 1.125rem;		/* 18 / 16 */
}
.caps,
figure,
footer {
	font-size: 14px;
	font-size: 0.875rem;		/* 14 / 16 */
}

Sexy? Maybe not. But this hybrid approach leaves us with resizable text in rem-compliant browsers, with a pixel-based fallback for older ones—a match made in heaven.

Pixels, ems, and rems—oh my!

Eames once said that “details are not details. They make the product.” And though it might not look like it, your approach to font-sizing is no different. Despite our personal preferences--whether you prefer slinging px or em, or have started dabbling in rem--each approach has its unique drawbacks and strengths, its own unique contributions to the project you're working on.

Pixels do afford us a high degree of precision, but at the expense of versatility. And while ems offer us both the control we crave and the accessibility we need, there's a certain amount of overhead with the contextual math involved. I could easily see rems being the way forward, but are px-based fallbacks an appropriate trade-off?

Who can say, really? Recently, Typekit’s own Jason Santa Maria said something similar:

Design is a multifaceted problem. How something behaves is interdependent on how it looks, sounds, reads, moves, and responds. We can’t separate these from the end result, but we can divide and conquer them during the creative process. Web design is not merely building. It’s not just designing. It’s not only the rest of the myriad disciplines and titles we all align ourselves with, but the culmination of all these things.

Ultimately, the approach you take should solve the multifaceted problems unique to your particular project. And whether those solutions use em, px, or rem, I can't wait to see how you've applied them.