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.
@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.
@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.
.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.
<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.
| Value | Behavior | Best For |
|---|---|---|
swap | Shows fallback text immediately, swaps to icon font when loaded | Icon fonts (recommended) |
block | Hides text briefly (up to 3s), then shows fallback | Text fonts where flash is distracting |
fallback | Short block (~100ms) + short swap (~3s) | Good balance for text fonts |
optional | Browser may skip the font entirely on slow connections | Non-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.
<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-Originheaders on the server. Alternatively, use thecrossoriginattribute 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-familyname in the icon class doesn't match the name in the@font-facedeclaration. 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.
.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.
@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.