You will be able to define a custom font in CSS with @font-face, load a self-hosted font file, and apply it to page text with a safe fallback stack.
What it is
@font-face is a CSS at-rule that tells the browser: “When you see this font family name, download this font file and use it.” The name you choose, such as 'Brand', is not a real font name; it is an alias you create for your CSS. The real font data comes from the file listed in src.
The mental model is a bridge between a CSS name and a font resource. You declare the bridge once, then use the name in normal font properties. Related terms include web font, font stack, fallback font, font format, and font-display.
Why it matters
- Brand control: You can use a font that is not installed on the user’s device.
- Consistent design: Headings, buttons, and body text can match your design system.
- Performance control: Self-hosting lets you choose file formats, caching, and loading behavior.
- Privacy: Fonts are served from your own domain instead of a third-party CDN.
- Offline or restricted environments: A local font file can work when external font services are blocked.
Syntax or steps
The smallest useful pattern has two parts: declare the font, then use it.
@font-face {
font-family: 'Brand';
src: url('brand.woff2') format('woff2');
font-display: swap;
}
body {
font-family: 'Brand', system-ui, sans-serif;
}
Steps:
- Place a font file, such as
brand.woff2, in your project. - Write an
@font-facerule with a customfont-familyname. - Point
srcto the file and declare its format. - Use the custom name in a normal CSS font stack.
Example
/* styles.css */
@font-face {
font-family: 'Brand';
src: url('/fonts/brand.woff2') format('woff2');
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Brand';
src: url('/fonts/brand-bold.woff2') format('woff2');
font-weight: 700;
font-style: normal;
font-display: swap;
}
body {
font-family: 'Brand', system-ui, sans-serif;
font-weight: 400;
}
h1 {
font-family: 'Brand', serif;
font-weight: 700;
}
Part by part:
font-family: 'Brand'creates the CSS alias.src: url('/fonts/brand.woff2') format('woff2')tells the browser where the font file is and what format it is.font-weight: 400andfont-weight: 700map normal and bold text to separate files.font-display: swapshows fallback text first, then swaps to the custom font when it loads.- The body and heading rules use the alias with fallbacks, so text remains readable if the font fails.
Common mistakes
- Wrong file path: If
url()cannot find the file, the font silently falls back. Check the path relative to the CSS file or use an absolute path like/fonts/brand.woff2. - Missing fallback: Writing
font-family: 'Brand';alone can leave text in a default font if loading fails. Use'Brand', system-ui, sans-serif. - Not declaring weight or style: If you use
font-weight: 700but only define a 400 file, the browser may synthesize bold. Add a separate@font-facefor each weight and style you need. - Using an unsupported format: WOFF2 is the best modern choice. If you must support very old browsers, add WOFF or TTF fallbacks in the same
srclist.
When to use it
Self-hosting with @font-face is best when you need full control over the font file. A hosted font service is often easier for common fonts.
| Approach | Best when | Trade-off |
|---|---|---|
Self-hosted @font-face | You have a brand font, need privacy, or must control caching and loading. | You manage files, formats, and updates. |
| Google Fonts or CDN | You want a quick, common web font without hosting files. | Depends on a third-party service. |
| System fonts | Performance and simplicity matter more than exact brand typography. | Appearance varies by device. |
Practice
Guided exercise: Create a folder named fonts, add a file named my-font.woff2, and write an @font-face rule for 'MyFont'. Apply it to body with a fallback.
@font-face {
font-family: 'MyFont';
src: url('/fonts/my-font.woff2') format('woff2');
font-display: swap;
}
body {
font-family: 'MyFont', system-ui, sans-serif;
}
Expected result: page text uses MyFont if the file loads; otherwise it uses the system fallback.
Challenge: Add a bold version of the same font family. Hint: create another @font-face block with the same font-family name but font-weight: 700 and a bold file.
Quick check
Question: Why include format('woff2') in the src value?
Answer: It tells the browser the file format, helping it decide whether the font is usable and reducing unnecessary downloads.
Summary
@font-face lets CSS connect a custom font name to a font file you control. The key is to declare the font once, use it with a fallback stack, and match weights and styles to the files you provide.