← Back to Generator

How to Use @font-face in CSS: Complete Guide

The @font-face CSS at-rule is how you embed custom fonts on your website. It tells the browser where to find font files, what to call them, and how to handle loading. This guide covers everything you need to know — from basic syntax to advanced performance optimization.

Basic @font-face Syntax

At its simplest, a @font-face declaration defines a font-family name and the source URL of the font file:

@font-face {
  font-family: 'MyCustomFont';
  src: url('fonts/MyCustomFont-Regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

Once declared, you can use this font anywhere in your CSS:

body {
  font-family: 'MyCustomFont', -apple-system, sans-serif;
}

Format Fallbacks

To maximize browser compatibility, you can list multiple font formats. The browser will use the first format it supports:

@font-face {
  font-family: 'MyCustomFont';
  src: url('MyCustomFont.woff2') format('woff2'),
       url('MyCustomFont.woff') format('woff');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

In 2026, WOFF2 + WOFF covers virtually all browsers. For details on when you might need additional formats, see our WOFF2 vs WOFF format guide.

Multiple Weights and Styles

For a font family with multiple weights and styles, create a separate @font-face block for each combination. This ensures browsers can correctly match weights and styles:

/* Regular */
@font-face {
  font-family: 'MyCustomFont';
  src: url('MyCustomFont-Regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* Bold */
@font-face {
  font-family: 'MyCustomFont';
  src: url('MyCustomFont-Bold.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* Italic */
@font-face {
  font-family: 'MyCustomFont';
  src: url('MyCustomFont-Italic.woff2') format('woff2');
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}

Important: Use the same font-family name for all weights/styles. The browser uses the font-weight and font-style descriptors to select the correct file. Do not create separate family names like 'MyFont-Bold'.

The font-display Property

The font-display property controls what happens while the custom font is loading. This is critical for user experience and Core Web Vitals:

Value Behavior Best For
swap Shows fallback font immediately, swaps when custom font loads ✅ Most websites (recommended)
block Hides text briefly (~3s), then shows fallback if font hasn't loaded Icon fonts, logo text
fallback Short block period (~100ms), then shows fallback Body text with small fonts
optional Browser decides based on connection speed Non-critical decorative fonts
auto Browser default (usually similar to block) Not recommended

Preloading Critical Fonts

For fonts used in above-the-fold content (headings, hero text), use <link rel="preload"> to tell the browser to fetch them as early as possible:

<link rel="preload"
      href="/fonts/MyCustomFont-Bold.woff2"
      as="font"
      type="font/woff2"
      crossorigin>

Use preloading sparingly — only for 1–2 critical font files that affect LCP. Preloading too many fonts can actually hurt performance by competing for bandwidth with other critical resources.

Local Font Matching

If the user already has the font installed on their system, you can skip the download entirely using the local() function:

@font-face {
  font-family: 'MyCustomFont';
  src: local('My Custom Font'),
       local('MyCustomFont-Regular'),
       url('MyCustomFont-Regular.woff2') format('woff2'),
       url('MyCustomFont-Regular.woff') format('woff');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

The Webfont Generator has a "Add Local Rule" toggle that automatically includes local() declarations in the generated CSS.

FOIT vs FOUT: Understanding Flash Problems

When using custom web fonts, you'll encounter two common rendering issues:

  • FOIT (Flash of Invisible Text): Text is completely hidden until the custom font loads. This happens with font-display: block and can feel broken to users.
  • FOUT (Flash of Unstyled Text): A fallback font is shown first, then swapped to the custom font. This is what font-display: swap produces. While there's a visible flash, text is always readable.

FOUT is almost always preferable to FOIT — users can read your content immediately, and the swap is usually subtle. This is why font-display: swap is the recommended default.

Self-Hosting vs. Google Fonts CDN

While Google Fonts is convenient, self-hosting your web fonts has several advantages:

Factor Self-Hosted Fonts Google Fonts CDN
Privacy ✅ No third-party tracking ❌ Google collects visitor data
Performance ✅ Same-origin, no DNS lookup ⚠️ Extra DNS + connection time
GDPR Compliance ✅ No third-party data transfer ❌ Potential legal issues in EU
Reliability ✅ Independent of third-party uptime ⚠️ Depends on Google CDN
Control ✅ Full control over subsetting & caching ❌ Google decides what to serve

Use a webfont generator to convert and subset Google Fonts (or any font) for self-hosting — you get better performance, full privacy, and GDPR compliance.

Complete Production Example

Here's a production-ready setup for a two-weight font system with preloading, fallbacks, and proper font stacking:

<!-- In your HTML <head> -->
<link rel="preload" href="/fonts/Inter-Regular.woff2"
      as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/fonts/Inter-Bold.woff2"
      as="font" type="font/woff2" crossorigin>

<style>
@font-face {
  font-family: 'Inter';
  src: url('/fonts/Inter-Regular.woff2') format('woff2'),
       url('/fonts/Inter-Regular.woff') format('woff');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Inter';
  src: url('/fonts/Inter-Bold.woff2') format('woff2'),
       url('/fonts/Inter-Bold.woff') format('woff');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

body {
  font-family: 'Inter', -apple-system, BlinkMacSystemFont,
    'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
}
</style>

Checklist for Production

  • ✅ Convert fonts to WOFF2 (with WOFF fallback)
  • Subset to only the characters you need
  • ✅ Use font-display: swap
  • ✅ Preload 1–2 critical font files
  • ✅ Self-host for privacy and performance
  • ✅ Include proper font-weight and font-style descriptors
  • ✅ Test with real content before deploying

Generate Your @font-face Code Automatically →