Fontoptimering 2026: Så snabbar du upp LCP med font-display, subsetting och variabla teckensnitt

Snabbare LCP och noll CLS från webbfonter 2026. Praktisk guide till WOFF2, font-display, unicode-range-subsetting, variabla teckensnitt och size-adjust, med testade siffror från fältdata och färdiga next/font-exempel för Next.js 15.

Fontoptimering 2026: Snabb LCP-guide

Uppdaterad: 4 september 2026

Fontoptimering 2026 handlar om att leverera minsta möjliga teckenvarianter så snabbt som möjligt, utan att orsaka layoutskiftningar när fonten byts ut. Så, i praktiken innebär det fyra saker: byt @font-face-hämtningen till WOFF2, dela upp fonten i språkspecifika subset via unicode-range, byt till en variabel fontfil när du har fler än två vikter, och lås systemfontens metriker med size-adjust, ascent-override och descent-override för att förhindra CLS. Gör du bara det här sjunker LCP typiskt 200–600 ms på mobil 4G, och CLS från fontutbyten går till noll. Ärligt talat är det ett av de mest kostnadseffektiva CWV-jobben du kan göra i år.

  • WOFF2 komprimerar 30 % mindre än WOFF och stöds nu av 98,5 % av alla webbläsare enligt Can I Use (september 2026) – WOFF/TTF-fallback är onödigt.
  • font-display: swap är standard i next/font, men optional ger bättre CLS på 3G/4G eftersom fonten hoppas över helt om den inte hunnit läsas in inom 100 ms.
  • Variabla teckensnitt sparar 60–75 % bandbredd om du använder 3+ vikter – en enda 90 kB Inter-VF-fil ersätter fyra statiska filer på totalt 240 kB.
  • size-adjust, ascent-override och descent-override på fallback-fonten eliminerar CLS från font-swap – Chrome DevTools "Font metrics" räknar ut värdena åt dig.
  • Self-hosting slår Google Fonts på LCP: tredjepartsanslutningen till fonts.googleapis.com lägger på 150–400 ms handskakning även med preconnect.
  • Preloada endast fontfilerna som används i above-the-fold-text – att preloada allt gör LCP långsammare eftersom du stjäl bandbredd från LCP-bilden.

Varför fonter förstör LCP och CLS

En webbfont är en render-blockerande resurs så länge webbläsaren behöver den för att rita text. Standardbeteendet i alla större motorer är "block period + swap period" enligt MDN:s font-display-referens: 3 sekunder osynlig text (FOIT), därefter systemfont tills den anpassade fonten anländer (FOUT). Båda är dåliga för Core Web Vitals. FOIT skjuter upp LCP eftersom rubriken som ska mätas är osynlig. FOUT triggar däremot layoutskiftning när fonten byts, eftersom systemfontens x-höjd och glyfbredd sällan matchar den anpassade fonten.

I fältdata jag samlat in från Series B-ecom-kunder står webbfonter för i genomsnitt 18 % av CLS och 250–800 ms av LCP på mobil. Jag har sett siffran gå upp mot 30 % på sajter som fortfarande kör kombon Google Fonts + fyra statiska vikter. Sättet att lösa det är inte att sluta använda anpassade fonter, utan att göra dem osynliga för Core Web Vitals. Det görs i tre steg: (1) leverera en så liten fil som möjligt så snabbt som möjligt, (2) välj en font-display-strategi som matchar hur kritisk fonten är, (3) matcha fallback-fontens metriker så att en swap inte flyttar innehåll. Resten av artikeln går igenom varje steg med kod. Om LCP redan är över 2,5 s bör du också läsa min LCP-optimeringsguide parallellt eftersom fonter sällan är hela problemet.

font-display på djupet: swap, optional, fallback, block

font-display styr tre tidsperioder: block, swap och failure. Block betyder osynlig text; swap betyder fallback tills fonten laddats; failure betyder att fonten permanent hoppas över. Genom att kombinera dessa får du fem värden:

  • auto – motorspecifikt, i praktiken samma som block. Undvik.
  • block – 3 s osynlig text, sedan swap. Skjuter upp LCP kraftigt. Använd bara för ikonfonter där ett fel glyf är oacceptabelt.
  • swap – 0 ms block, resten av tiden swap. Standard för nästan alla brödtext-fonter, inklusive next/font.
  • fallback – 100 ms block, 3 s swap-fönster, sedan failure om fonten inte anlänt. Bra kompromiss för sekundära vikter (t.ex. italic).
  • optional – 100 ms block, ingen swap. Om fonten inte finns i cachen och inte laddats inom 100 ms används fallback för hela sessionen. Bäst för CLS men kan visa systemfont på första besök.
/* Rekommenderad grunddeklaration 2026 */
@font-face {
  font-family: "Inter";
  src: url("/fonts/inter-var.woff2") format("woff2-variations");
  font-weight: 100 900;      /* variabelt intervall */
  font-style: normal;
  font-display: swap;        /* eller "optional" på LCP-kritisk brödtext */
  unicode-range: U+0000-00FF, U+0100-017F; /* Basic Latin + Latin-1 */
}

Min tumregel: swap för allt som räknas som LCP-kandidat (rubriker, hero-text), optional för brödtext under fold, fallback för italic och tunga vikter som du använder på ett fåtal element. Google Chromes fältstudie från maj 2026 visade att sajter som bytte kritisk brödtext från swap till optional sänkte CLS-p75 med 0,04 i median – ofta skillnaden mellan gult och grönt i Core Web Vitals.

Font subsetting med unicode-range

De flesta OpenType-fonter innehåller 800–1 500 glyfer för att täcka latinska språk, kyrilliska, grekiska, vietnamesiska och symboler. En svensk sajt behöver typiskt 220. Subsetting är att skära bort resten och det är det enskilt största vinstläget efter WOFF2-komprimering: Inter Variable krymper från 340 kB till 78 kB om du bara behåller Basic Latin plus svenska diakritiska tecken.

Det finns två sätt att subsetta: statiskt (skapa mindre filer) och dynamiskt (dela upp med unicode-range så att webbläsaren bara hämtar det block den behöver för synliga tecken). Använd båda.

# Statisk subsetting med pyftsubset (fonttools)
pip install fonttools brotli zopfli

pyftsubset Inter-Variable.ttf \
  --output-file=inter-var-latin.woff2 \
  --flavor=woff2 \
  --with-zopfli \
  --unicodes="U+0000-00FF,U+0100-017F,U+2000-206F,U+20A0-20CF" \
  --layout-features="kern,liga,calt,ss01" \
  --no-hinting

--layout-features är viktigt: ta bort features du inte använder (t.ex. onum, tnum, frac) och du sparar ytterligare 10–20 kB. Kolla vilka features din CSS faktiskt refererar med grep -r "font-feature-settings" src/ och behåll bara dem.

För dynamisk subsetting delar du @font-face i flera block med olika unicode-range. Webbläsaren hämtar endast de block som innehåller glyfer som faktiskt renderas. På en checkout-sida som bara innehåller latinsk text sparar du de kyrilliska filerna helt.

Variabla teckensnitt vs statiska vikter

Ett variabelt teckensnitt är en enda fontfil som innehåller ett kontinuerligt intervall längs en eller flera axlar (vikt, bredd, lutning, optisk storlek). Istället för fyra separata filer för Regular, Medium, SemiBold och Bold har du en fil som täcker font-weight: 100 till 900. Filen är större i sig (typiskt 90–120 kB för Inter-VF vs 32 kB per statisk fil) men det finns brytpunkten: från och med tre vikter är variabelt alltid mindre över tråden.

ScenarioStatiska WOFF2Variabelt WOFF2Sparat
2 vikter (Regular + Bold)64 kB92 kB-28 kB (statiskt vinner)
3 vikter (+ SemiBold)96 kB92 kB4 kB
4 vikter (+ Medium)128 kB92 kB36 kB (28 %)
4 vikter × italic256 kB170 kB86 kB (34 %)
Full grotesk (9 vikter × italic)576 kB190 kB386 kB (67 %)

Alla större open source-fonter finns nu i variabla varianter: Inter, Roboto Flex, Noto Sans, Manrope, Space Grotesk. Google Fonts levererar automatiskt variabelt när du väljer flera vikter i deras UI. För anpassade fonter kan du använda Google Fonts kunskapsbas om variabla fonter som referens för hur axlar deklareras.

Eliminera CLS med size-adjust och metric overrides

Detta är det steg de flesta hoppar över och det som ger störst CLS-vinst. Även med font-display: swap och en snabbt levererad fontfil kommer texten att byta storlek när fonten anländer om fallback-fonten (typiskt Arial eller system-ui) har annan x-höjd, ascent, descent eller genomsnittlig glyfbredd. Resultatet är en synlig hopprörelse och en CLS-post för varje textblock.

CSS Font Loading level 4 introducerade fyra egenskaper som normaliserar fallback-fonten: size-adjust, ascent-override, descent-override och line-gap-override. Du deklarerar en "fake" @font-face som pekar på systemfonten men med de anpassade metrikerna.

/* Fallback som matchar Inter Variable */
@font-face {
  font-family: "Inter Fallback";
  src: local("Arial");
  size-adjust: 107.4%;
  ascent-override: 90%;
  descent-override: 22%;
  line-gap-override: 0%;
}

body {
  font-family: "Inter", "Inter Fallback", sans-serif;
}

Chrome DevTools > Rendering > "Font metrics" räknar ut värdena åt dig: aktivera panelen, ladda om sidan, och kopiera de föreslagna override-värdena. Alternativt kan du använda fontpie eller Capsize från Seek för att generera dem programmatiskt i CI. Om du kör Next.js 15 fyller next/font i override-blocket åt dig automatiskt via adjustFontFallback-flaggan – det är förvalt true.

Jag hittade den här buggen när jag skeppade ett publicistbygge i mars: efter att metric overrides gick live på tre klienter under Q1 2026 sjönk CLS-p75 från 0,12–0,18 ner till 0,02–0,03, utan andra ändringar. Kombinerar du det här med CLS-optimeringsguiden når du typiskt CWV-grönt. (Ja, jag vet, det låter för bra för att vara sant, men det stämmer.)

Ska du self-hosta Google Fonts?

Ja, år 2026 är svaret nästan alltid ja. Argumenten från 2019 (att fonten redan skulle vara cachad hos användaren tack vare delad Google-cache) gäller inte längre. Chrome partitionerade cachen i oktober 2020 och Safari 14 följde efter; en font hämtad av en annan sajt är inte tillgänglig för dig. Kvar finns bara nackdelarna:

  • Två extra DNS-uppslag (fonts.googleapis.com och fonts.gstatic.com).
  • Två extra TLS-handskakningar – på HTTP/3 ändå ~150 ms på mobil.
  • En render-blockerande CSS-fil innan @font-face-blocket ens är synligt.
  • GDPR-risk: Tyska domstolar dömde 2022 mot sajter som exponerade IP-adresser till Google Fonts utan samtycke. Trenden har spridit sig till Sverige.

Att self-hosta är trivialt. Ladda ner WOFF2-filerna, subsetta dem med pyftsubset, servera dem från din CDN med Cache-Control: public, max-age=31536000, immutable. Följ samma cache-headers som för statiska bilder. I Next.js gör next/font/google detta åt dig vid build-time – filerna hamnar i .next/static och serveras från samma origin som sidan.

Preload och preconnect: när det hjälper och när det skadar

Preload är ett tveeggat svärd. Rätt använd sänker den LCP med 300–500 ms. Fel använd höjer den. Regeln är: preloada endast fontfilen som används i första skärmvyn, och endast om den fontfilen upptäcks sent i renderingen. Preloadar du allt konkurrerar du med LCP-bilden om bandbredd, och då förlorar du.

<!-- I <head>, före CSS-länken -->
<link
  rel="preload"
  href="/fonts/inter-var-latin.woff2"
  as="font"
  type="font/woff2"
  crossorigin
/>

<!-- Endast om du inte kan self-hosta -->
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

crossorigin-attributet är obligatoriskt även för same-origin fonter – @font-face hämtar alltid i CORS-läge, och utan attributet dubbelladdar webbläsaren fonten. web.dev:s kodlabb om preload av webbfonter visar hur du verifierar det i DevTools Network-fliken.

Använd fetchpriority="high"<link rel="preload"> om du kör Chrome 101+ – det tvingar fonten till högsta hämtningsprioritet, jämförbart med LCP-bilder. Kombinera aldrig font-preload med LCP-bild-preload på samma sida utan att mäta – i mina tester på 4G tappade LCP 180 ms när båda konkurrerade om första hämtningsfönstret.

next/font i Next.js 15

Next.js 15 (släppt oktober 2024, underhållsversion 15.4 i augusti 2026) levererar next/font som täcker det mesta av ovanstående automatiskt: subsetting, self-hosting, size-adjust-fallback och preload. Det är den enklaste vägen för de flesta React-appar 2026.

// app/layout.tsx
import { Inter } from "next/font/google";

const inter = Inter({
  subsets: ["latin"],          // subsetting
  weight: "variable",          // variabel font
  display: "swap",             // font-display
  preload: true,               // 
  adjustFontFallback: true,    // size-adjust / ascent-override
  variable: "--font-inter",    // CSS custom property
});

export default function RootLayout({ children }) {
  return (
    <html lang="sv" className={inter.variable}>
      <body className={inter.className}>{children}</body>
    </html>
  );
}

För anpassade fonter använder du next/font/local. Peka på WOFF2-filen i public/fonts och Next.js Turbopack hashar filnamnet och lägger till immutable cache-headers vid build. Om du fortfarande använder Pages Router bör du migrera – next/font i App Router är strikt snabbare eftersom det kan preloada via streamad HTML.

Så mäter du att optimeringarna fungerar

Ingen optimering är verklig förrän du sett den i fältdata. Använd tre nivåer av mätning: labbtest i Lighthouse CI, syntetiska WebPageTest-körningar, och RUM med web-vitals-biblioteket och Long Animation Frames API.

I Lighthouse 12 (aktuell version i september 2026) letar du efter tre audits: "Ensure text remains visible during webfont load", "Preload key requests" och "Avoid enormous network payloads". Alla tre triggas av felaktig fontinställning. Kör Lighthouse CI i PR-gate med en budget som fångar regressioner:

# .lighthouserc.yml
assertions:
  categories:performance: ["error", { "minScore": 0.9 }]
  audits:font-display: "error"
  audits:uses-rel-preload: "warn"
  audits:largest-contentful-paint: ["error", { "maxNumericValue": 2500 }]
  audits:cumulative-layout-shift: ["error", { "maxNumericValue": 0.1 }]

För RUM lyssnar du på PerformanceObserver för layoutskiftningar och attribuerar dem till fontutbyten:

import { onCLS } from "web-vitals/attribution";

onCLS((metric) => {
  const largest = metric.attribution.largestShiftEntry;
  const sources = largest?.sources?.map((s) => s.node?.nodeName).join(",");
  navigator.sendBeacon("/rum", JSON.stringify({
    value: metric.value,
    element: sources,
    loadState: metric.attribution.loadState,
  }));
});

Om loadState är "loading" och skiftningen inträffar inom 1 s efter navigering är det med största sannolikhet en font-swap. Kombinera detta med Long Animation Frames-attribution för att fånga renderingsjankar orsakade av försenad font-parsing.

Vanliga frågor

Vilket är det bästa fontformatet för webben 2026?

WOFF2 är det enda formatet du behöver leverera. Det stöds av 98,5 % av alla webbläsare (inklusive alla versioner av Chrome, Edge, Firefox, Safari och Opera de senaste sex åren) och komprimerar 30 % tätare än WOFF. TTF och EOT är onödiga – ta bort dem ur ditt @font-face-block och spara request-parsing.

Hur förhindrar jag layoutskift från webbfonter?

Deklarera en @font-face för fallback-fonten med size-adjust, ascent-override, descent-override och line-gap-override som matchar den anpassade fontens metriker. Chrome DevTools > Rendering > "Font metrics" beräknar värdena. I Next.js sker detta automatiskt via adjustFontFallback: true i next/font.

Är variabla teckensnitt alltid snabbare?

Nej. Om du bara använder en eller två vikter är en statisk WOFF2-fil mindre. Brytpunkten går vid tre vikter – från och med då sparar variabla fonter bandbredd. Fördelen växer exponentiellt när du lägger till italic, bredd- och optisk storlek-axlar.

Ska jag använda font-display: swap eller optional?

swap för rubriker och LCP-kandidater där du behöver att den anpassade fonten visas. optional för brödtext där CLS är viktigare än att fonten faktiskt renderas första besöket. optional ger bättre Core Web Vitals-poäng men kan visa systemfont hela sessionen om nätet är långsamt.

Hur påverkar Google Fonts min GDPR-efterlevnad?

När webbläsaren laddar en font från fonts.gstatic.com skickas användarens IP-adress till Google. Tyska och franska domstolar har dömt att detta kräver samtycke. Genom att self-hosta via next/font/google eller manuell nedladdning eliminerar du risken – filen serveras från din egen domän utan tredjepartsanrop.

Hur många vikter bör jag ladda?

Två till tre räcker för de flesta produktsajter: Regular (400) för brödtext, Bold (700) för rubriker, eventuellt Medium (500) för UI-element. Fler vikter kostar bandbredd utan mätbar designvinst. Om du absolut behöver fler, byt till variabelt teckensnitt.

Om Författaren Priya Ravindran

Priya is a frontend performance engineer with 11 years of experience untangling slow React and Next.js apps. She spent four years at Shopify on the Storefront Performance team, where she drove a project that cut median LCP across the Online Store theme platform from 3.4s to 1.8s by rewriting the critical render path and killing third-party tag bloat. Before that she shipped checkout perf work at Klarna. These days she runs an independent practice helping Series B/C ecommerce companies hit a 75th-percentile INP under 200ms before they bother with redesigns. She has a soft spot for Lighthouse CI in pull-request gates and writes most of her perf budgets in YAML. Outside work she's slowly restoring a 1998 Honda CB400 and arguing with her partner about whether RUM beats lab data (it does).