Resource Hints 2026: preload, preconnect ja modulepreload käytännön opas
preload, preconnect, modulepreload ja fetchpriority käytännössä: milloin käyttää mitäkin, miten välttää yleiset virheet ja miten mitata todellinen vaikutus LCP:hen vuonna 2026.
Resource hints ovat <link>-tagin variantteja (preload, preconnect, dns-prefetch, prefetch, modulepreload), joilla kerrot selaimelle etukäteen, mitä alkuperiä tai tiedostoja se tulee tarvitsemaan (ja millä prioriteetilla). Oikein sijoiteltuna resource hint parantaa Largest Contentful Paintia (LCP) tyypillisesti 200–800 ms, koska selain ehtii käynnistää DNS-haun, TLS-kättelyn tai varsinaisen tiedostonlatauksen aiemmin kuin HTML-jäsentäjä muuten löytäisi resurssin. Käydään läpi jokainen hint-tyyppi, milloin niitä kannattaa käyttää ja miten mitata todellinen vaikutus vuonna 2026.
preload on tarkoitettu resursseille, jotka selain löytää liian myöhään (esim. CSS:n @font-face tai JS:n dynaamisesti lataamat kuvat), ei koskaan koko sivun jokaiselle tiedostolle.
preconnect lyhentää kolmannen osapuolen alkuperän ensimmäistä pyyntöä 100–300 ms, koska DNS + TCP + TLS tehdään etukäteen. Käytä sitä vain 3–4 tärkeimmälle origin-osoitteelle.
modulepreload on ES-moduuleille sama mitä preload on kuville: se lataa moduulin JA sen riippuvuudet etukäteen, mihin preload ei pysty.
prefetch hakee resurssin matalalla prioriteetilla seuraavaa navigointia varten. Vuonna 2026 sen rooli menee osin päällekkäin Speculation Rules API:n kanssa.
fetchpriority="high" on nykyään suositeltavampi tapa priorisoida jo löydetty resurssi kuin lisätä sille erillinen preload.
HTTP Early Hints (103-vastaus) mahdollistaa resource hintien lähettämisen jo ennen kuin HTML-dokumentti on ehditty generoida.
Mikä on resource hint?
Resource hint on selaimelle annettu ohje, joka kertoo "tämä resurssi kannattaa aloittaa hakea nyt" tai "tämä alkuperä kannattaa avata nyt". Standardit on määritelty W3C:n Resource Hints -spesifikaatiossa (preconnect, dns-prefetch, prefetch, prerender) ja täydennetty myöhemmin Preload-spesifikaatiolla sekä HTML Living Standardin modulepreload-lisäyksellä. Jokainen hint annetaan HTML:n <head>-osiossa <link rel="...">-elementillä tai HTTP-otsakkeella Link:.
Vuonna 2026 tuki on käytännössä universaali: Chromium, Firefox ja Safari toteuttavat kaikki viisi hint-tyyppiä. Erot ovat lähinnä siinä, miten selain päättää, mitkä hintit toteutuvat matalalla verkonkuormalla ja mitkä hylätään. Esimerkiksi Chromium rajoittaa yhtäaikaisten preconnect-yhteyksien määrää, joten "kaiken varalta"-listaus ei auta. Se saattaa jopa hylätä oikeasti tärkeimmän vihjeen.
Resource hintit ovat myös monin tavoin vanhempien menetelmien "kutsuja": Speculation Rules API on niiden modernimpi ja tarkempi seuraaja navigointien ennakointiin, ja fetchpriority-attribuutti korvaa monia entisiä preload-käyttötapauksia. Käymme molemmat läpi omissa osioissaan.
preload: kriittisten resurssien lataus etukäteen
<link rel="preload"> pakottaa selaimen aloittamaan resurssin latauksen välittömästi ja korkealla prioriteetilla, ennen kuin HTML-jäsentäjä on ehtinyt kohdata varsinaista viittausta. Preloadista on hyötyä silloin, kun resurssi löytyy vasta myöhäisessä vaiheessa: esimerkiksi @font-face-säännön kautta ladattava fontti, JavaScriptin dynaamisesti lisäämä hero-kuva tai reitityksen kautta ladattava JS-lohko.
Käyttö vaatii aina as-attribuutin, joka kertoo selaimelle resurssin tyypin (tämä ohjaa oikean prioriteetin ja Content Security Policy -tarkistuksen). Fonttien preloadissa tarvitaan lisäksi crossorigin-attribuutti, muuten selain tekee toisen pyynnön eikä käytä preload-vastausta. Törmäsin tähän itse viime projektissa: fontti latautui kahdesti, ja huomasin sen vasta DevToolsin Network-välilehdeltä.
<!-- Kriittinen fontti, jota @font-face lataa CSS:stä -->
<link rel="preload"
href="/fonts/inter-var.woff2"
as="font"
type="font/woff2"
crossorigin>
<!-- LCP-kuva, joka renderöidään JS:n toimesta -->
<link rel="preload"
href="/img/hero.avif"
as="image"
type="image/avif"
fetchpriority="high">
<!-- Reitin lohko, jonka React ladataan lazy()-funktiolla -->
<link rel="preload"
href="/assets/route-checkout.js"
as="script">
Käytännön muistisääntö: preloadaa vain, jos resurssi täyttää sekä ehdon "kriittinen renderöinnille" että "selain löytäisi sen liian myöhään ilman vihjettä". Jos kuva on jo <img src>-tagissa HTML:ssä, preload ei nopeuta sitä. Selain löysi sen jo. Käytä sen sijaan fetchpriority="high"-attribuuttia (katso alempi osio).
preconnect ja dns-prefetch: yhteyden avaus ennakkoon
Kun selain lataa ensimmäistä kuvaa, fonttia tai skriptiä ulkoiselta alkuperältä (esimerkiksi https://cdn.example.com), ensimmäinen pyyntö sisältää DNS-haun, TCP-kättelyn ja TLS-neuvottelun. Nämä voivat viedä 100–300 ms mobiiliverkossa, jopa ennen kuin varsinainen HTTP-pyyntö lähtee. preconnect tekee kaikki nämä vaiheet etukäteen. dns-prefetch puolestaan hoitaa vain DNS-haun.
<!-- Täysi yhteys valmiiksi (DNS + TCP + TLS) -->
<link rel="preconnect" href="https://cdn.example.com" crossorigin>
<link rel="preconnect" href="https://fonts.googleapis.com" crossorigin>
<!-- Fallback: pelkkä DNS-haku vanhemmille selaimille tai kevyempiin tarpeisiin -->
<link rel="dns-prefetch" href="https://analytics.example.com">
crossorigin-attribuutti tarvitaan aina, kun preconnect osoittaa alkuperään, jolta ladataan CORS-tilassa käytettäviä resursseja (kaikki fontit ja moduulit ovat CORS). Ilman sitä selain avaa yhteyden ei-credentialed-tilassa, ja fonttilataus joutuu avaamaan uuden yhteyden. Hukkaan mennyt vihje siis.
Käytännön kynnysarvo: preconnectaa vain 3–4 tärkeintä origin-osoitetta. Chromium hylkää liialliset preconnectit hiljaisesti, ja jokainen avoin TLS-yhteys vie asiakkaan puolella muistia. Jos ulkoisia origin-alkuperiä on kymmeniä (esimerkiksi mainoseko-järjestelmä), yhdistele niitä kolmannen osapuolen skriptien optimoinnin periaatteilla ja käytä dns-prefetchiä loppuihin.
modulepreload: ES-moduulien esilataus
ES-moduulit poikkeavat tavallisista skripteistä siten, että jokainen import-lause aiheuttaa uuden verkkopyynnön. Riippuvuusgraafin syvyys näkyy suoraan latenssina, koska selain ei löydä lapsimoduulia ennen kuin vanhempi on jäsennetty. <link rel="modulepreload"> ratkaisee tämän: se lataa moduulin JA sen kaikki staattiset riippuvuudet etukäteen ja jäsentää ne muistiin valmiiksi.
Modernit bundlerit (Vite 6, Rollup 4, esbuild) tuottavat modulepreload-tagit automaattisesti tuotantobuildin yhteydessä. Jos rakennat manuaalisen HTML:n, luettele riippuvuudet importmapin tai bundle-analyysin perusteella. Älä preloadaa tavallisellarel="preload" as="script"-tagilla, sillä se ei kerro selaimelle moduuligraafin tarpeista eikä käytä oikeaa MIME-tarkistusta.
prefetch: seuraavan navigoinnin ennakointi
<link rel="prefetch"> hakee resurssin matalalla prioriteetilla ja tallettaa sen HTTP-välimuistiin tulevaa käyttöä varten. Tyypillinen käyttö on ladata seuraavan reitin JS-lohko, kun käyttäjä hyvin todennäköisesti navigoi sinne (esim. kassalle etenevän ostosprosessin seuraava vaihe).
Vuonna 2026 Speculation Rules API on monessa käyttötapauksessa parempi valinta, koska se voi prerenderata koko sivun eikä pelkästään hakea siihen liittyviä resursseja. Prefetch säilyttää kuitenkin roolinsa, kun halutaan säästää HTTP-välimuistiin resurssit ilman että selain käynnistää täyttä renderöintiä (esim. mobiililaitteet, joilla prerender kuluttaisi liikaa muistia).
fetchpriority: priorisointi resource hintien rinnalla
fetchpriority-attribuutti (nimetty aiemmin Priority Hints -nimellä) on tapa säätää jo löydetyn resurssin prioriteetti ilman erillistä preload-elementtiä. Se hyväksyy arvot "high", "low" ja "auto", ja toimii <img>, <link>, <script> ja fetch()-kutsuissa.
<!-- LCP-kuva: kerro selaimelle että tämä on ykkösprioriteetti -->
<img src="/img/hero.avif" alt="..." fetchpriority="high">
<!-- Ei-kriittinen jakopainike: matala prioriteetti -->
<img src="/img/share-icon.png" alt="Jaa" fetchpriority="low">
<!-- Kolmannen osapuolen widget-skripti -->
<script src="https://widget.example.com/embed.js" fetchpriority="low" async></script>
// Fetch API
fetch("/api/critical-data", { priority: "high" });
Käytännön ohje: jos LCP-kuvasi on <img>-tagissa HTML:ssä, käytä fetchpriority="high" ennen kuin lisäät preloadin. Preload on tarpeen vain silloin, kun resurssi paljastuu selaimelle myöhäisessä vaiheessa. Tämä muutos näkyy myös meidän LCP-optimoinnin oppaassa: suositus on siirtynyt viime vuosina preloadeista fetchpriorityn suuntaan.
Chromen tiimin mittausten mukaan pelkkä fetchpriority="high" LCP-kuvassa parantaa LCP:tä keskimäärin 10 %. Yksityiskohtaiset benchmark-tulokset ja tuen tilanne löytyvät Chromen fetchpriority-dokumentaatiosta.
HTTP Early Hints (103): palvelimen puolen resource hints
Early Hints on HTTP-vastauskoodi 103, jolla palvelin voi lähettää selaimelle resource hint -otsakkeita jo ennen varsinaisen 200-vastauksen valmistumista. Tästä on hyötyä erityisesti dynaamisilla sivuilla, joilla palvelinlogiikka vie 100–500 ms. Selain voi käyttää tuon ajan preconnect- tai preload-toimintoihin.
Tuki: Cloudflare, Fastly ja Vercel Edge Network tukevat Early Hintsiä automaattisesti tai Link-otsakkeen kautta. Node.js Express ei toteuta 103-vastausta suoraan. Tarvitset alempaa http.ServerResponse.prototype.writeEarlyHints()-API:a, joka on saatavilla Node 18+.
Early Hints on erityisen hyvä pari TTFB-optimoinnin kanssa: jos TTFB on korkea eikä sitä saada helposti alas, Early Hints antaa selaimelle työtä tekeväksi odotuksen ajaksi. Tuen ja rajoitusten yksityiskohdat: Chromen Early Hints -esittely.
Yleiset virheet ja miten välttää ne
Resource hintit tuovat suorituskyvyllisiä hyötyjä vain, jos niitä käytetään säästeliäästi ja oikeissa paikoissa. Alla on yleisimmät sudenkuopat, joita näen jatkuvasti asiakastarkastuksissa vuonna 2026.
1. Preloadataan kaikki, mikä kriittiseltä näyttää
Kymmenen preload-tagia hero-osiossa ei nopeuta mitään. Ne kaikki kilpailevat samasta kaistasta ja pääsäikeen jäsennysajasta. Rajaa preloadit yhteen fonttiin (tai kahteen jos kyseessä on latinalainen + kyrillinen), yhteen LCP-kuvaan ja mahdollisesti yhteen kriittiseen JS-lohkoon.
2. Unohdetaan crossorigin-attribuutti
Fonttien ja moduulien preload ilman crossorigin-attribuuttia johtaa siihen, että selain hakee resurssin uudestaan, kun sen todella tarvitsee. Sama koskee preconnectiä CORS-alkuperille. DevToolsin Network-välilehti näyttää duplikaatin, joten tarkista sieltä ensimmäisenä.
3. Preloadataan resurssi, joka on jo HTML:ssä
Jos <img src="/hero.avif"> on jo dokumentissa, preload on tarpeeton. HTML-preload-scanner löytää sen jo. Käytä sen sijaan fetchpriority="high".
4. Käytetään dns-prefetchiä siinä missä preconnect toimisi
Kaikki modernit selaimet tukevat preconnectiä. Käytä sitä tärkeille alkuperille, ja säilytä dns-prefetch varjoutensa vain erittäin harvinaiselle vanhalle liikenteelle tai listalle, jossa on kymmeniä origin-osoitteita eikä preconnectin täyttä kustannusta voida maksaa jokaisesta.
5. Prefetchataan liikaa
Jokainen prefetch kuluttaa käyttäjän dataliikennettä, vaikka hän ei koskaan navigoisikaan sinne. Mobiilikäyttäjät maksavat tästä. Rajaa prefetchit todennäköisimpiin seuraaviin sivuihin (esim. checkout-flow'ssa maksimissaan yksi eteenpäin).
Miten mittaan resource hintien vaikutusta?
Resource hint -muutokset kannattaa mitata sekä lab- että kenttädatalla, koska niiden vaikutus riippuu voimakkaasti verkon latenssista ja laitteesta. Lab-mittauksessa vertaa saman sivun latausta ennen ja jälkeen muutoksen: WebPageTestin "Compare"-näkymässä näkyy tarkalleen, milloin fontti tai LCP-kuva alkoi latautua.
// PerformanceObserver LCP-elementin ja sen resurssin ajastukseen
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log("LCP:", entry.startTime, "ms");
console.log("Element:", entry.element);
console.log("URL:", entry.url);
}
}).observe({ type: "largest-contentful-paint", buffered: true });
// Resource Timing API kertoo, onko preload toteutunut
performance.getEntriesByType("resource")
.filter(r => r.initiatorType === "link")
.forEach(r => console.log(r.name, r.responseEnd - r.startTime));
Kenttädatassa käytä web-vitals-kirjastoa keräämään todelliset LCP-arvot käyttäjiltä ja segmentoi tulokset laitetyypin (mobiili/desktop) ja verkkonopeuden (navigator.connection.effectiveType) mukaan. Chromen sisäisten tutkimusten mukaan hyvin sijoiteltu preload parantaa 75. persentiilin LCP:tä noin 200–500 ms, kun taas huono preload voi jopa hidastaa sitä 50–100 ms. Törmäsin tähän itse eräässä verkkokauppa-auditoinnissa: kolme "varmuuden vuoksi"-preloadia söi LCP-kuvalta kaistan, ja niiden poisto pudotti mobiilin p75-LCP:tä lähes puoli sekuntia. Lisää mittauskäytännöistä web.dev:n preload-oppaassa.
Lighthouse 12 raportoi kolme relevanttia diagnostiikkaa: "Preconnect to required origins", "Preload key requests" ja "Preloaded but not used within 3 seconds". Jälkimmäinen on 2026-version tärkein. Se sakottaa turhista preloadeista, joten seuraa sitä osana CI-putken suorituskykytarkistuksia. MDN:n preload-attribuutin dokumentaatio antaa täydellisen listan tuetuista as-arvoista.
Usein kysytyt kysymykset
Mikä on ero preload ja prefetch välillä?
preload hakee resurssin korkealla prioriteetilla nykyiselle sivulle ja pakottaa selaimen käyttämään sen ennen renderöintiä. prefetch puolestaan hakee resurssin matalalla prioriteetilla myöhempää navigointia varten ja tallettaa sen HTTP-välimuistiin. Preload = "tarvitsen tämän nyt, älä unohda", prefetch = "saatan tarvita tätä myöhemmin, hae kun on kaistaa vapaana".
Milloin kannattaa käyttää preconnectiä?
Käytä preconnectiä kolmelle tai neljälle tärkeimmälle ulkoiselle alkuperälle, joilta ladataan kriittisiä resursseja (fontteja, CDN-kuvia, API-kutsuja) ensimmäisen renderöinnin aikana. Yli neljä preconnectiä ei enää anna hyötyä, ja Chromium saattaa jopa hylätä ylimääräiset vihjeet.
Tarvitaanko dns-prefetch vielä vuonna 2026?
Harvoin. Kaikki modernit selaimet tukevat preconnectiä, joka tekee DNS-haun lisäksi TCP- ja TLS-neuvottelun. dns-prefetch on hyödyllinen vain vanhoille selaimille (esim. IE11-legacy-koodi) tai kun sivustolla on kymmeniä ulkoisia origin-osoitteita ja täyden preconnectin kustannus olisi liian suuri jokaiselle.
Estääkö preload pääsäikeen?
Ei suoraan, lataus tapahtuu verkossa. Ladattu resurssi (esim. CSS tai skripti) joutuu kuitenkin jäsentäjän käsittelyyn, mikä voi lisätä pääsäikeen työtä. Siksi preloadien liikakäyttö voi hidastaa renderöintiä, vaikka verkkolataukset itsessään ovat rinnakkaisia.
Mikä on modulepreload ja miten se eroaa preloadista?
modulepreload lataa ES-moduulin sekä sen kaikki staattiset riippuvuudet etukäteen ja jäsentää ne muistiin valmiiksi. Tavallinen preload as="script" hakee vain yhden tiedoston eikä osaa seurata import-lauseita. Käytä aina modulepreloadia moduulikoodille.
Kannattaako käyttää fetchpriority vai preload LCP-kuvalle?
Jos LCP-kuva on jo suoraan HTML:n <img>-tagissa, käytä fetchpriority="high". Preload on tarpeen vain silloin, kun kuva paljastuu vasta CSS- tai JS-koodin ajamisen jälkeen (esimerkiksi taustakuva tai lazy-lisätty elementti).
Käytännön opas responsiivisiin kuviin vuonna 2026: srcset ja sizes oikein, AVIF/WebP-fallback picture-elementillä, lazy loading ja fetchpriority LCP:n parantamiseksi. Sisältää valmiit koodiesimerkit, kuvaputken ohjeet ja Lighthouse-tarkistuslistan.
Miten hallita HTTP-välimuistia oikein 2026: Cache-Control-direktiivit, stale-while-revalidate ja CDN-invalidointi Cloudflaressa, Fastlyssa ja Vercelissä. Kaavat, koodit ja mittausohjeet.
Käytännön opas kolmannen osapuolen skriptien optimointiin 2026: mittaus LoAF-API:lla, facade-kuvio raskaille upotuksille, Partytown web workerissa ja bundle-budjetit CI:ssä. Sisältää valmiit koodinäytteet ja verkkokaupasta poimitut mittaustulokset.