The font-display descriptor controls **how web fonts load and render** on your website. It defines what the browser should do **while the custom font is loading**, and how it should behave if the font takes too long to load or fails entirely.
Note
β Crucial for performance and avoiding invisible text (FOIT)
β Affects how quickly text appears to users
π¦ Syntax
@font-face with font-display
@font-face {
font-family: "MyFont";
src: url("myfont.woff2") format("woff2");
font-display: swap;
}| Value | Behavior |
|---|---|
| auto | Browser decides |
| block | Text invisible briefly, then custom font appears |
| swap | Text shows immediately using fallback, then swaps to custom |
| fallback | Shows fallback instantly, swaps only if font loads quickly |
| optional | Fallback shown; custom font used only if cache/quick |
π¨ Understanding font-display Modes
1οΈβ£ font-display: auto
Default behavior. Browser chooses strategy depending on connection, font size, etc.
2οΈβ£ font-display: block (FOIT β Invisible Text)
block
@font-face {
font-family: "MyFont";
src: url("font.woff2");
font-display: block;
}The browser hides text until the font loads (up to 3 seconds). After that, text appears in custom font or fallback if failed.
Note
3οΈβ£ font-display: swap (Recommended)
swap
@font-face {
font-family: "MyFont";
src: url("font.woff2");
font-display: swap;
}Text appears immediately using fallback font β once custom font loads, the text βswapsβ to the custom font.
Note
4οΈβ£ font-display: fallback
fallback
@font-face {
font-family: "MyFont";
src: url("font.woff2");
font-display: fallback;
}Text uses fallback font first. Custom font replaces it only if loaded within ~100ms.
5οΈβ£ font-display: optional (Best for very fast sites)
optional
@font-face {
font-family: "MyFont";
src: url("font.woff2");
font-display: optional;
}If the font loads instantly (from cache), it appears. Otherwise, the browser **sticks to the fallback font permanently**.
Note
π― Visual Comparison
| Mode | Initial Text | After Font Loads |
|---|---|---|
| block | β Invisible | β Custom |
| swap | β Fallback visible | β Switches to custom |
| fallback | β Fallback visible | β οΈ Swaps only if fast |
| optional | β Fallback visible | β οΈ Usually remains fallback |
π§ͺ Real-World Use Cases
1οΈβ£ Best for UI Websites β swap
UI font loading
@font-face {
font-family: "Inter";
src: url("Inter.woff2");
font-display: swap; /* best UI experience */
}2οΈβ£ Article / Blog Typography β fallback
blog
@font-face {
font-family: "Merriweather";
src: url("Merriweather.woff2");
font-display: fallback;
}3οΈβ£ Performance-First Apps β optional
performance
@font-face {
font-family: "Poppins";
src: url("poppins.woff2");
font-display: optional;
}Prevents layout shift on slow networks.
β οΈ Common Mistakes
- β Using block on text-heavy websites (causes invisible text)
- β Assuming font-display works outside @font-face
- β Not providing fallback fonts (system-ui, serif, sans-serif)
- β Using large unoptimized fonts (slows down swap)
Note
π₯ Summary
font-display determines how your text behaves while custom fonts load. Choosing the right mode is crucial for UX, speed, and visual stability.
- swap β Best balance (recommended)
- fallback β Good for reading content
- optional β Top performance option
- block β Avoid unless necessary