<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Zerrin Arslan</title>
    <description>The latest articles on DEV Community by Zerrin Arslan (@fontbox).</description>
    <link>https://dev.to/fontbox</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3985925%2F9ae2704d-e311-4789-831a-b5c5a349a3ac.png</url>
      <title>DEV Community: Zerrin Arslan</title>
      <link>https://dev.to/fontbox</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fontbox"/>
    <language>en</language>
    <item>
      <title>Adding custom fonts to a Next.js app without the layout shift</title>
      <dc:creator>Zerrin Arslan</dc:creator>
      <pubDate>Mon, 15 Jun 2026 17:38:38 +0000</pubDate>
      <link>https://dev.to/fontbox/adding-custom-fonts-to-a-nextjs-app-without-the-layout-shift-5657</link>
      <guid>https://dev.to/fontbox/adding-custom-fonts-to-a-nextjs-app-without-the-layout-shift-5657</guid>
      <description>&lt;p&gt;If you've used Next.js in the last couple of years you've probably reached for &lt;code&gt;next/font&lt;/code&gt;. It's genuinely great — but I still see custom fonts done in ways that tank the Lighthouse score or make the page jump around on load. Here's how I actually wire up fonts in a Next.js app now, and the one thing that quietly fixes most of the layout shift.&lt;/p&gt;

&lt;h2&gt;
  
  
  Google fonts: &lt;code&gt;next/font/google&lt;/code&gt; already self-hosts
&lt;/h2&gt;

&lt;p&gt;First, a thing a lot of people miss: &lt;code&gt;next/font/google&lt;/code&gt; doesn't load anything from Google's servers at runtime. At build time Next downloads the font files and serves them from your own origin. So you get the self-hosting win (no third-party request on the critical path) for free:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Inter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/font/google&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Inter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;subsets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;latin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;swap&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;RootLayout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;inter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/body&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;subsets: ["latin"]&lt;/code&gt; line matters — it subsets the file so you're not shipping glyphs for languages you don't use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom / paid fonts: &lt;code&gt;next/font/local&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;For a font that isn't on Google Fonts — a brand font, a freebie you downloaded, whatever — use &lt;code&gt;next/font/local&lt;/code&gt; and point it at a WOFF2 in your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;localFont&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/font/local&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;localFont&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./fonts/MyFont-Regular.woff2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;400&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;normal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./fonts/MyFont-Bold.woff2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="na"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;700&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;normal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;swap&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;variable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--font-display&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then expose it as a CSS variable and use it wherever:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;variable&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.heading&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--font-display&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your font is a &lt;code&gt;.ttf&lt;/code&gt;/&lt;code&gt;.otf&lt;/code&gt;, convert it to WOFF2 first — smaller and supported everywhere. I usually just drop it into &lt;a href="https://fontboxdl.com/tools/webfont-generator" rel="noopener noreferrer"&gt;FontBoxDL's webfont generator&lt;/a&gt; (browser-based, no install) and grab the WOFF2 back. And if you're still hunting for the font itself, the &lt;a href="https://fontboxdl.com/" rel="noopener noreferrer"&gt;free library&lt;/a&gt; has a pile of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The thing that actually fixes layout shift
&lt;/h2&gt;

&lt;p&gt;Here's the part people skip. Even with &lt;code&gt;display: swap&lt;/code&gt;, when the real font swaps in it usually has different metrics than the fallback — so text reflows and your CLS spikes. &lt;code&gt;next/font&lt;/code&gt; can fix this automatically if you give it a fallback to match against:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;localFont&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./fonts/MyFont-Regular.woff2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;swap&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;system-ui&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;arial&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;adjustFontFallback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Arial&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// generates a size-adjusted @font-face for the fallback&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;adjustFontFallback&lt;/code&gt; makes Next emit a fallback &lt;code&gt;@font-face&lt;/code&gt; with &lt;code&gt;size-adjust&lt;/code&gt;/&lt;code&gt;ascent-override&lt;/code&gt; tuned so the fallback occupies almost exactly the same space as your real font. The swap becomes nearly invisible. This one prop has done more for my CLS numbers than anything else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick gotchas
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Don't import a font inside a component that re-renders.&lt;/strong&gt; Declare it at module scope (top of the file), once. Importing it in the render path defeats the optimization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;variable&lt;/code&gt; vs &lt;code&gt;className&lt;/code&gt;:&lt;/strong&gt; use &lt;code&gt;className&lt;/code&gt; if it's your single global font; use &lt;code&gt;variable&lt;/code&gt; when you want multiple fonts available as CSS custom properties.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Preload is automatic&lt;/strong&gt; for fonts used on the route — you don't need a manual &lt;code&gt;&amp;lt;link rel="preload"&amp;gt;&lt;/code&gt; like you would in a plain HTML setup.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  TL... actually, no TL;DR
&lt;/h2&gt;

&lt;p&gt;Use &lt;code&gt;next/font/google&lt;/code&gt; for Google fonts (it self-hosts), &lt;code&gt;next/font/local&lt;/code&gt; for everything else, ship WOFF2, and set &lt;code&gt;adjustFontFallback&lt;/code&gt; so the swap doesn't shove your layout around. Takes ten minutes and your Core Web Vitals will thank you.&lt;/p&gt;

&lt;p&gt;What's your go-to for custom fonts in Next — &lt;code&gt;next/font/local&lt;/code&gt;, or do you still hand-roll the &lt;code&gt;@font-face&lt;/code&gt;?&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>webdev</category>
      <category>fonts</category>
    </item>
    <item>
      <title>I stopped loading fonts from Google's CDN — here's the self-hosting setup that stuck</title>
      <dc:creator>Zerrin Arslan</dc:creator>
      <pubDate>Mon, 15 Jun 2026 16:42:33 +0000</pubDate>
      <link>https://dev.to/fontbox/i-stopped-loading-fonts-from-googles-cdn-heres-the-self-hosting-setup-that-stuck-2lpm</link>
      <guid>https://dev.to/fontbox/i-stopped-loading-fonts-from-googles-cdn-heres-the-self-hosting-setup-that-stuck-2lpm</guid>
      <description>&lt;p&gt;For years I just dropped the Google Fonts &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; in my &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; and moved on. One line, done, who cares. Right?&lt;/p&gt;

&lt;p&gt;Then I was staring at a Lighthouse report for a landing page that &lt;em&gt;felt&lt;/em&gt; sluggish, and there it was in the waterfall: a render-blocking hop to &lt;code&gt;fonts.googleapis.com&lt;/code&gt;, then a second one to &lt;code&gt;fonts.gstatic.com&lt;/code&gt; for the actual file. Two extra connections — DNS lookup, TLS handshake, the whole dance — before a single character painted. On my laptop? Invisible. On a mid-range Android over flaky mobile data? Very visible.&lt;/p&gt;

&lt;p&gt;So I bit the bullet and self-hosted. Took an afternoon, and I've done it on every project since. Here's the setup I've landed on after a bunch of trial and error.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get a WOFF2 (and only WOFF2)
&lt;/h2&gt;

&lt;p&gt;WOFF2 is supported literally everywhere now and it's ~30% smaller than the old WOFF. You don't need the &lt;code&gt;.ttf&lt;/code&gt;, &lt;code&gt;.eot&lt;/code&gt;, &lt;code&gt;.svg&lt;/code&gt; fallback zoo from 2014 anymore. Just ship WOFF2.&lt;/p&gt;

&lt;p&gt;If you've got a &lt;code&gt;.ttf&lt;/code&gt;/&lt;code&gt;.otf&lt;/code&gt;, convert it with fonttools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;fonttools brotli
fonttools ttLib.woff2 compress MyFont.ttf   &lt;span class="c"&gt;# -&amp;gt; MyFont.woff2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Honestly I got tired of doing the CLI thing for one-off fonts, so I ended up building a little browser tool for it — &lt;a href="https://fontboxdl.com/tools/webfont-generator" rel="noopener noreferrer"&gt;FontBoxDL's webfont generator&lt;/a&gt; — drop a TTF/OTF in, get WOFF2 + a &lt;code&gt;@font-face&lt;/code&gt; block back, no install. Use whatever's less friction for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The @font-face block
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@font-face&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;"MyFont"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url("/fonts/myfont.woff2")&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;"woff2"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;400&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;normal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;font-display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;swap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The line that matters most here is &lt;code&gt;font-display: swap&lt;/code&gt;. It tells the browser "show the fallback text immediately, swap in the real font when it arrives." Without it you get FOIT — invisible text while the font loads — which is a worse experience than a quick font flash, basically every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preload the one font that matters
&lt;/h2&gt;

&lt;p&gt;Drop this in your &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"preload"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/fonts/myfont.woff2"&lt;/span&gt; &lt;span class="na"&gt;as=&lt;/span&gt;&lt;span class="s"&gt;"font"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"font/woff2"&lt;/span&gt; &lt;span class="na"&gt;crossorigin&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things people get wrong here, me included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Don't preload everything.&lt;/strong&gt; Preload only the font(s) you actually use above the fold. If you preload six weights, you've just created a different bottleneck.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't forget &lt;code&gt;crossorigin&lt;/code&gt;.&lt;/strong&gt; I once left it off and spent a solid 20 minutes confused about why the font was being downloaded &lt;em&gt;twice&lt;/em&gt;. Fonts are always fetched in CORS mode, so the preload has to match or the browser throws your preloaded copy away.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Subset if you care about bytes
&lt;/h2&gt;

&lt;p&gt;A full font ships thousands of glyphs you will never render. If your site is English/Latin, subsetting can knock off 70%+:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pyftsubset MyFont.ttf &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--unicodes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"U+0000-00FF"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--flavor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;woff2 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;myfont.subset.woff2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I don't always bother for a single light body font, but for display/heading fonts it's an easy win.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cache it like it'll never change (because it won't)
&lt;/h2&gt;

&lt;p&gt;Fingerprint the filename, then cache forever:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Cache-Control: public, max-age=31536000, immutable
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Don't skip the fallback stack
&lt;/h2&gt;

&lt;p&gt;Even with &lt;code&gt;swap&lt;/code&gt;, give it a real fallback so the first paint looks intentional and the layout doesn't lurch when the swap happens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;"MyFont"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;-apple-system&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BlinkMacSystemFont&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;"Segoe UI"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roboto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;That's the whole thing. Convert → &lt;code&gt;@font-face&lt;/code&gt; with &lt;code&gt;swap&lt;/code&gt; → preload the critical one (with &lt;code&gt;crossorigin&lt;/code&gt;!) → cache hard. It's maybe an hour of work and you get a real LCP/CLS improvement plus one fewer third party in your critical path.&lt;/p&gt;

&lt;p&gt;Anyone still on the Google CDN &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; for production — what's keeping you there? Genuinely curious if there's a case I'm missing.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>css</category>
      <category>performance</category>
      <category>fonts</category>
    </item>
  </channel>
</rss>
