squirrelscan
GitHub

font-display swap: the @font-face rule squirrel looks for

An @font-face block with no font-display, or Google Fonts loaded without a preconnect. squirrel reads the inline CSS on every page.

What font-display does

A web font arrives after the HTML. Until it does, the browser has to decide what to draw. With no font-display the strategy is auto, which leaves the choice to the browser; in practice that is a short period with the text invisible, then a swap to the real font. On a slow connection that period shows as a page with no text in it.

font-display: swap makes the choice explicit: draw the fallback font immediately, swap when the web font arrives. The text reflows on the swap unless the fallback’s metrics are matched to the web font, but it is readable the whole time. optional is the stricter option, which uses the web font only if it arrives almost instantly and never shifts the text.

What squirrel checks

The rule runs on every crawled page and emits one or two checks:

  • font-display: warns with the message N font(s) without font-display: swap and lists each family name as an item. It passes with All fonts have font-display set when every block declares one.
  • font-preconnect: emitted only on a page that loads a stylesheet from fonts.googleapis.com. It warns with the message Using Google Fonts without preconnect and the value Add <link rel='preconnect' href='https://fonts.gstatic.com' crossorigin> when no link[rel="preconnect"] points at fonts.googleapis.com or fonts.gstatic.com. Otherwise it passes with Google Fonts preconnect configured.

The @font-face scan is a regular expression over the page’s raw HTML, so it sees blocks written inline in a <style> element and blocks that happen to appear anywhere else in the markup. It does not fetch external stylesheets, so a font declared in a linked CSS file is not checked. A block counts as declared when the case-sensitive text font-display appears anywhere inside it, including in a comment. The family name is read from the block’s font-family value, or reported as Unknown font when there is none.

The Google Fonts usage test matches any <link href> resolving to fonts.googleapis.com, whatever its rel, so a preconnect to that host on a page with no Google Fonts stylesheet counts as usage. Fonts pulled in with @import are not detected as usage at all.

Elements inside <noscript> are skipped: a browser with scripting enabled reads <noscript> content as plain text, so nothing in it loads or renders. See content inside noscript.

How to fix it

@font-face {
  font-family: "Inter";
  src: url("/fonts/inter.woff2") format("woff2");
  font-display: swap;
}

Add the descriptor to every block. When a hosted service serves the CSS, the display parameter does the same thing:

<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter&display=swap" />

The limit worth knowing is a site whose @font-face blocks live in an external stylesheet. The rule reads the page HTML only, so it finds no blocks and passes, whatever those blocks say.

Rule IDperf/font-loading
CategoryPerformance
ScopePer-page
Severitywarning
Weight5/10

Enable / disable

Disable this rule

[rules]
disable = ["perf/font-loading"]

Disable all Performance rules

[rules]
disable = ["perf/*"]

Enable only this rule

[rules]
enable = ["perf/font-loading"]

enable replaces the default ["*"], so this is the only rule selected. Leave disable out: a rule that matches any disable pattern is skipped even when enable names it. Only an enabled setting under a rule’s own [rule_options] table overrides both lists.

Performance findings ship in every audit next to the SEO, security and agent experience rules. See Core Web Vitals for how an agent works through a report.

References

Check your site

Run squirrel audit https://example.com and open the Performance section of the report. Each font family without a display descriptor is listed by page. Signed-out local audits need no account and cost nothing. Signed-in audits spend credits.

Type to search…

↑↓ navigate↵ openesc close