Using preload or preconnect for font assetsfor Drupal 11 , 10 , 9 , and 8

Last updated :  

Custom web fonts are a common, easy-to-miss source of layout shift and delayed text rendering: the browser has to discover the font file is needed, fetch it, and only then can it render text in that font — sometimes showing invisible text or a fallback font swap in the meantime. Two small HTML hints, preload and preconnect, tell the browser to get a head start.

What you'll learn in this lesson

  • The difference between preconnect (warm up a connection) and preload (start fetching a specific file)
  • How to attach a preload hint through Drupal's library system, the right way — not by hand-editing a Twig template's <head>
  • Why font-display: swap is a complementary, not competing, technique

preconnect vs preload

  • preconnect — tells the browser to establish the DNS/TCP/TLS connection to a domain early, before you know exactly which file you'll need from it. Useful when fonts are served from an external host like Google Fonts.
  • preload — tells the browser to start fetching one specific, known file immediately, at high priority, well before it would otherwise discover it (e.g. buried inside a CSS @font-face rule that itself has to load first).

Attaching a preload hint through a library

Rather than hardcoding a <link> tag into a template, declare it as an attached HTML head element in your theme's *.libraries.yml, keeping it cacheable and themeable like any other asset:

my_theme.font-preload:
  header: true
  dependencies: []
function my_theme_preprocess_html(array &$variables) {
  $variables['#attached']['html_head_link'][] = [
    [
      'rel' => 'preload',
      'href' => '/themes/custom/my_theme/fonts/heading.woff2',
      'as' => 'font',
      'type' => 'font/woff2',
      'crossorigin' => 'anonymous',
    ],
    TRUE,
  ];
}
Don't preload fonts you don't render on every page. A preloaded font the browser never actually uses is pure wasted bandwidth and can trigger a console warning. Reserve preloading for the handful of fonts genuinely used above the fold on most pages — usually just your body and heading fonts, not every weight/style variant you own.

The complementary technique: font-display

Preloading gets the file sooner; font-display: swap in your @font-face CSS rule controls what happens if it still isn't ready yet — showing text immediately in a fallback font, then swapping to the custom font once it arrives, rather than leaving text invisible. Use both together for the best result: preload to shrink the wait, swap to make any remaining wait invisible to the reader.

See it for yourself

After adding a preload hint, view your page's source — you should see a <link rel="preload" as="font" ...> tag in the <head>. In browser dev tools' Network tab, that font request should now show a much higher priority and start earlier than it did before.

Quick check: you preloaded a font file, but your Lighthouse report still flags "unused preload" for it. What went wrong? (The preloaded font isn't actually referenced by any CSS @font-face rule that gets applied on that page — preload only helps if the browser goes on to genuinely need that exact file.)

Key takeaways

  • preconnect warms up a connection to a domain; preload fetches one specific known file at high priority.
  • Attach preload hints through your theme's library/preprocess system (#attached['html_head_link']), not by hand-writing markup into a template.
  • Only preload fonts you actually render on most pages — an unused preload wastes bandwidth and produces a Lighthouse warning.
  • Pair preloading with font-display: swap in your CSS to avoid invisible text while any remaining wait plays out.

Coming up next

Fonts are one render-blocking resource; the next lesson looks at render-blocking CSS/JS more broadly — Reducing Render-Blocking Resources.