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) andpreload(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: swapis 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-facerule 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,
];
}
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-facerule that gets applied on that page — preload only helps if the browser goes on to genuinely need that exact file.)
Key takeaways
preconnectwarms up a connection to a domain;preloadfetches 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: swapin 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.