CSS @font-face

The CSS rule that makes icon fonts work on the web — declaring, loading, and using custom font files in your stylesheets.

The Basics

@font-face is the CSS at-rule that tells the browser where to find a font file and what to call it. It was first supported in IE 4 back in 1997, but only became practical across browsers around 2010 when WOFF arrived and other browsers implemented the rule consistently.

For icon fonts, @font-face is the glue between your font files and the CSS classes that display icons. Without it, the browser has no way to know that font-family: 'MyIcons' should load a specific file from your server.

Basic syntax
@font-face {
  font-family: 'MyIcons';
  src: url('fonts/myicons.woff2') format('woff2');
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

The font-family descriptor gives the font a name you'll reference later. The src descriptor tells the browser where to download the file and what format it's in. The font-weight and font-style descriptors ensure the browser doesn't try to synthesize bold or italic variants. And font-display controls what happens while the font is loading.

The Modern Font Stack

The format() hint after each URL tells the browser which format the file is in, so it can skip formats it doesn't support without downloading them first. Over the years, the recommended set of formats has narrowed dramatically as browser support has improved.

Modern (recommended)
@font-face {
  font-family: 'MyIcons';
  src: url('myicons.woff2') format('woff2');
  font-display: swap;
}

With 97%+ browser coverage, WOFF2 alone is sufficient for the vast majority of modern projects. This is the simplest and most performant approach.

With WOFF fallback (IE 11 support)
@font-face {
  font-family: 'MyIcons';
  src: url('myicons.woff2') format('woff2'),
       url('myicons.woff') format('woff');
  font-display: swap;
}

Adding WOFF as a fallback covers IE 11, which doesn't support WOFF2. Modern browsers will grab the WOFF2 file; IE 11 falls through to WOFF.

Full legacy stack (IE 6-8 support)
@font-face {
  font-family: 'MyIcons';
  src: url('myicons.eot');                    /* IE9 compat */
  src: url('myicons.eot?#iefix') format('embedded-opentype'),
       url('myicons.woff2') format('woff2'),
       url('myicons.woff') format('woff'),
       url('myicons.ttf') format('truetype');
  font-display: swap;
}

The full "bulletproof" stack includes EOT for IE 6-8, WOFF2 for modern browsers, WOFF for IE 9-11, and TTF as a final fallback. The browser tries each src entry in order and uses the first format it understands. This approach is only necessary for projects with extreme legacy requirements.

Using Icon Classes

The standard pattern for icon fonts uses a base class that sets the font-family and shared rendering styles, then individual icon classes that use ::before pseudo-elements with content set to each icon's Unicode code point.

CSS icon classes
.icon {
  font-family: 'MyIcons';
  font-style: normal;
  font-weight: normal;
  font-variant: normal;
  text-transform: none;
  line-height: 1;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.icon-home::before { content: '\E001'; }
.icon-search::before { content: '\E002'; }
.icon-user::before { content: '\E003'; }

The base class resets font styling to prevent the browser from applying bold, italic, or other transformations that would distort the icons. The -webkit-font-smoothing and -moz-osx-font-smoothing properties enable antialiasing for crisper rendering on macOS and iOS.

Each icon class sets a ::before pseudo-element with the Unicode code point assigned to that glyph. The backslash-E notation (\E001) is CSS's way of referencing a Unicode character by its hex code point.

HTML usage
<i class="icon icon-home"></i>
<span class="icon icon-search"></span>

Both <i> and <span> work equally well. The element itself is empty — the icon is rendered entirely by the ::before pseudo-element.

font-display

The font-display descriptor controls what the browser shows while the font file is still downloading. This is critical for icon fonts because the wrong setting can make icons invisible during page load.

ValueBehaviorBest For
swapShows fallback text immediately, swaps to icon font when loadedIcon fonts (recommended)
blockHides text briefly (up to 3s), then shows fallbackText fonts where flash is distracting
fallbackShort block (~100ms) + short swap (~3s)Good balance for text fonts
optionalBrowser may skip the font entirely on slow connectionsNon-essential decorative fonts

For icon fonts, swap is the recommended choice. A brief flash of unstyled content (where icon code points might appear as squares or blank spaces) is far better than invisible icons. With block, users could see empty space where icons should be for up to 3 seconds on slow connections — which looks like a broken page. With swap, the icons pop in as soon as the font loads, and the transition is usually imperceptible on modern connections.

Loading Optimization

Font files are render-blocking by default — the browser won't paint text using a custom font until the file has downloaded. Here are techniques to minimize the impact:

  • Preload the font file — use <link rel="preload"> to start downloading the font as early as possible, before the browser even parses the CSS that references it.
  • Self-host your fonts — serving font files from the same origin as your HTML avoids extra DNS lookups and connection setup, and eliminates CORS issues.
  • Subset your font — remove unused icons to reduce file size. A 500-icon font where you only use 50 icons is wasting 90% of the download.
  • Use unicode-range — if you have multiple icon sets, this descriptor tells the browser to only download the font file when characters in the specified range are actually used on the page.
Preloading the font file
<link rel="preload" href="fonts/myicons.woff2" as="font"
      type="font/woff2" crossorigin>

The crossorigin attribute is required even for same-origin fonts — this is a quirk of the font loading specification. Without it, the browser will download the font twice: once from the preload hint (without CORS) and once from the @font-face rule (with CORS).

Common Pitfalls

  • CORS errors — Font files served from a different origin (e.g., a CDN subdomain) need Access-Control-Allow-Origin headers on the server. Alternatively, use the crossorigin attribute on the <link> tag. Without proper CORS configuration, the browser will block the font silently.
  • Icons showing as squares or rectangles — This usually means the font file path is wrong, the font hasn't loaded yet, or the font-family name in the icon class doesn't match the name in the @font-face declaration. Check your browser's Network tab to confirm the font file loaded with a 200 status.
  • Icons showing wrong glyphs — Unicode code point conflicts with system fonts. If your icon font uses code points in ranges that overlap with common system fonts, the browser might render a system character instead. Icon fonts typically use the Private Use Area (U+E000 to U+F8FF) to avoid this.
Debugging tip
Open your browser's DevTools, go to the Network tab, and filter by "Font". You should see your .woff2 file with a 200 status. If it's missing, the path is wrong. If it shows a CORS error, check your server headers. If it loaded but icons still don't appear, inspect the element and verify the font-family matches exactly.
In Bobcorn
Bobcorn generates the complete CSS file for you — the @font-face declaration, the base .icon class, and individual icon classes with the correct Unicode code points. The CSS uses your chosen font name and references the font files with relative paths. Enable the CSS option in the export dialog to include it alongside your font files.