Illustration by

Using Webfonts

A note from the editors: We’re pleased to share an excerpt from Chapter 2 (“Using Webfonts") of Bram Stein's new book, Webfont Handbook, available now from A Book Apart.

Now that you’ve selected a font, let’s put it on your website. Webfonts are defined in CSS through the @font-face rule. If you’re a web developer, you’ve most likely written, copied and pasted, or at the very least seen an @font-face rule. For the sake of completeness, though, let’s quickly run through a basic example:

Article Continues Below
@font-face {
    font-family: Elena;
    src: url(elena-regular.woff);
}

This creates a new webfont family that can be referenced through the font-family or font shorthand property. But something’s missing here. When referencing a webfont in a font stack, always make sure to include at least one fallback font in case the webfont fails to load. Here, if Elena fails to load, the browser will fall back on the generic serif font family:

p {
    font-family: Elena, serif;
}

We’ll talk more about fallback fonts and how they can be used to make your site appear to load faster in Chapter 3. For now, let’s keep our fallback stack simple by including only the generic serif and sans-serif font families.

Font Families#section2

Creating a font family with multiple styles is accomplished by creating an @font-face rule for each style and using the same font-family name. The following @font-face rules create a family with a normal and bold style:

@font-face {
    font-family: Elena;
    src: url(elena-regular.woff);
    font-weight: normal;
}

@font-face {
    font-family: Elena;
    src: url(elena-bold.woff);
    font-weight: bold;
}

You can use this font family in your CSS by referencing the family name and weight in your selectors. This applies the regular style to paragraphs and the bold style to strong paragraphs:

p {
    font-family: Elena, serif;
}

p strong {
    font-weight: bold;
}

Besides font-weight, @font-face also accepts the font-style and font-stretch property descriptors, which define styles such as italic and condensed. All three property descriptors can be used to create a single font family with multiple styles. Theoretically, this lets you create a family containing 243 individual styles (nine font-weight values × three font-style values × nine font-stretch values). In practice, however, you’re limited to twenty-seven values, since some browsers don’t support font-stretch (Fig 2.1).

Internet Explorer 8 Internet Explorer 9-11 Edge Chrome Firefox Safari Opera Android System
No Yes Yes Yes Yes No Yes No
Fig 2.1: Browser support for font-stretch at time of writing. (Check caniuse.com for current and version-specific browser support.)

With luck, the remaining browsers will implement the font-stretch property soon, and you will be able to use all 243 font classifications.

Font Formats#section3

The src descriptor tells a browser where to get a font file. The previous examples used a single font format, but you’ll often see URLs to multiple font formats combined with format hints, which are appended after the URL using the format("value") syntax. Format hints tell the browser what the format of the font file at a given URL is.

@font-face {
    font-family: Elena;
    src: url(elena-regular.woff2) format("woff2"),
        url(elena-regular.woff) format("woff");
}

If you list multiple formats, modern browsers will pick the first format they support based on the format hint. Therefore, it’s important to list webfont formats in the order of best compression to least. Even though format hints are optional, always include them—they let the browser know about the format without needing to download the font. For example, if a browser does not support WOFF2, but does support WOFF, it can skip the WOFF2 font file based on the format hint.

Browsers support several webfont formats: OpenType (TrueType), EOT, WOFF, and WOFF2. Some browsers also support SVG fonts, but they’re deprecated and should no longer be used (and should not be confused with the new OpenType-SVG format). EOT, WOFF, and WOFF2 are technically not font formats. They are compressed OpenType files with varying degrees of compression. WOFF2 offers the best compression, followed by WOFF and EOT (Fig 2.2).

Format Internet Explorer 8 Internet Explorer 9-11 Edge Chrome Firefox Safari Opera Android System
WOFF2 No No Yes Yes Yes Yes Yes No
WOFF No Yes Yes Yes Yes Yes Yes Yes
OpenType No Yes Yes Yes Yes Yes Yes Yes
EOT Yes Yes No No No No No No
Fig 2.2: Browser support for font formats at the time of writing. Look for up-to-date and version-specific browser support for font formats at caniuse.com.

In researching coverage for all browsers, you may have come across something called the bulletproof @font-face syntax by Fontspring. The bulletproof syntax uses EOT, WOFF2, WOFF, raw OpenType, and SVG font files for maximum browser coverage:

@font-face {
    font-family: Elena;
    src: url(elena.eot?#iefix) format("embedded-opentype"),
         url(elena.woff2) format("woff2"),
         url(elena.woff) format("woff"),
         url(elena.otf) format("opentype"),
         url(elena.svg#elena) format("svg");
}

The first URL line might look a little odd to you. Versions of Internet Explorer 8 and below do not support the syntax for multiple font formats, and treat the entire value of the src property as the URL. The bulletproof syntax tricks Internet Explorer 8 and below into thinking that the remaining URLs are part of the fragment identifier of the first URL. Because fragment identifiers are ignored when downloading files, Internet Explorer 8 and below simply use the first URL. Browsers other than Internet Explorer will skip the line because they do not support EOT. The rest of the entries are what you would expect: font formats listed in order of preference.

But is the bulletproof syntax still relevant? No. In fact, I think it’s harmful. SVG fonts are deprecated and only supported by browsers that are no longer in use. Most websites support Internet Explorer 9 and up, yet the syntax lists EOT as the first preferred font format. Even though Internet Explorer 9 and up support WOFF, those versions will still download the EOT file, simply because it is listed first.

Because most websites no longer support old browsers, I highly recommend using a simplified syntax. This simplified syntax covers all modern browsers, as well as slightly older ones that are still in active use, such as Android 4.4 and earlier:

@font-face {
    font-family: Elena;
    src: url(elena.woff2) format("woff2"),
         url(elena.woff) format("woff"),
         url(elena.otf) format("opentype");
}

Even though older Android versions are still used, worldwide reliance on these browsers is rapidly dwindling. Soon you will probably be able to drop the raw OpenType format as well, and simplify the syntax even further:

@font-face {
    font-family: Elena;
    src: url(elena.woff2) format("woff2"),
         url(elena.woff) format("woff");
}

In this case, someone running an older browser will simply see your fallback fonts instead of the webfont. That’s fine; they can still read the content in the fallback font. (More on fallback fonts later.)

There’s another possible value for the src descriptor. The local function takes the name of a local font family. If the font happens to be installed on the system, the browser will use that instead, thereby avoiding an extra download.

@font-face {
    font-family: Elena;
    src: local("Elena"),
         url(elena-regular.woff2) format("woff2"),
         url(elena-regular.woff) format("woff");
}

While this may seem like a great optimization, nothing guarantees that the local font matches your webfont. You may get a different version of the font, a font with different language support, or even an entirely different font. For that reason, I usually recommend not using the local function unless you find these downsides acceptable.

Want to read more?#section4

This excerpt from Webfont Handbook will help you get started. Order the full copy today, as well as other excellent titles from A Book Apart.

Cover from Webfont Handbook

About the Author

Bram Stein

Bram Stein is a developer and product manager. He cares a lot about typography and is happiest working at the intersection between design and technology. In his spare time, he maintains Font Face Observer, Type Inspector, and several other tools for improving web typography. Bram writes for several magazines and is a contributing author to Smashing Book 5. He also speaks about typography and web performance at conferences around the world.

5 Reader Comments

  1. If IE8 ignores the part after the #, then the format doesn’t have to be valid. You can use:

    url(“elena.eot#iefix”) format(“ie8-only”)

    This will let IE9 and above skip this line since they don’t support the “ie8-only” format.

Got something to say?

We have turned off comments, but you can see what folks had to say before we did so.

More from ALA

I am a creative.

A List Apart founder and web design OG Zeldman ponders the moments of inspiration, the hours of plodding, and the ultimate mystery at the heart of a creative career.
Career