HTML Guides for font-display
Learn how to identify and fix common HTML validation errors flagged by the W3C Validator — so your pages are standards-compliant and render correctly across every browser. Also check our Accessibility Guides.
font-display controls how a font face is displayed based on whether and when it has been downloaded and is ready to use. Its accepted values — auto, block, swap, fallback, and optional — determine the behavior during the font-loading timeline (block period, swap period, and failure period). Because it governs the loading behavior of a font face definition, it only makes sense within a @font-face rule, not as a property applied to an HTML element.
When you place font-display inside a regular selector like body or .heading, the CSS validator correctly flags it as an unknown property. Browsers will silently ignore it, meaning your intended font-loading strategy won’t take effect. Users may experience a flash of invisible text (FOIT) or other unwanted behavior because the browser falls back to its default font-display strategy.
Why this matters
- Font-loading performance: Without a valid font-display descriptor in your @font-face rule, you lose control over how the browser handles text rendering while custom fonts load. Using font-display: swap, for example, ensures text remains visible with a fallback font until the custom font is ready — a key web performance best practice.
- Standards compliance: The CSS Fonts Module Level 4 specification defines font-display exclusively as a @font-face descriptor. Using it elsewhere produces invalid CSS.
- Silent failure: Browsers won’t throw visible errors — they simply ignore the invalid property, which can make it difficult to diagnose why your font-loading behavior isn’t working as expected.
How to fix it
- Remove font-display from any regular CSS rule (selectors like body, h1, .class, etc.).
- Add font-display inside the @font-face at-rule where you define your custom font.
- If you’re loading fonts via a third-party service (like Google Fonts), you can often append a &display=swap parameter to the font URL instead of writing your own @font-face block.
Examples
❌ Incorrect: font-display used as a CSS property
body {
font-family: "Open Sans", sans-serif;
font-display: swap;
}
This triggers the validator error because font-display is not a valid CSS property for element selectors.
✅ Correct: font-display used inside @font-face
@font-face {
font-family: "Open Sans";
src: url("/fonts/open-sans.woff2") format("woff2"),
url("/fonts/open-sans.woff") format("woff");
font-display: swap;
}
body {
font-family: "Open Sans", sans-serif;
}
Here, font-display: swap is correctly placed inside the @font-face rule, telling the browser to immediately render text with a fallback font and then swap in “Open Sans” once it finishes loading.
✅ Correct: Using display=swap with Google Fonts
If you use Google Fonts, you don’t need to write your own @font-face block. Instead, add the display parameter to the URL:
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Open+Sans&display=swap">
Google Fonts will generate the @font-face rules with font-display: swap included automatically.
❌ Incorrect: font-display in a class selector
.heading {
font-family: "Roboto", sans-serif;
font-display: optional;
}
✅ Correct: Separate the descriptor from the styling rule
@font-face {
font-family: "Roboto";
src: url("/fonts/roboto.woff2") format("woff2");
font-display: optional;
}
.heading {
font-family: "Roboto", sans-serif;
}
The font-display: optional descriptor now correctly lives in the @font-face block, where it tells the browser to use the custom font only if it’s already cached — otherwise, stick with the fallback. The .heading rule simply references the font family by name.
Ready to validate your sites?
Start your free trial today.