A Speculation Rules API: a böngésző már betölti a következő oldalt, mielőtt rákattintanál

A Chrome hover közben teljes oldalakat renderel le előre a Speculation Rules API-val – és van egy beállítási szint, ami évekig nem csinálta azt, amit a neve ígért.

Kattints egy linkre bármelyik modern hírportálon vagy webshopon Chrome-ban, és jó eséllyel a következő oldal már készen áll, mire a kurzor leér. Nem a szerver küldött semmi extrát, nem volt service worker cache, és nem is prefetch-elt <link> tag töltötte le előre a HTML-t a régi módon. A böngésző egyszerűen már legyártotta az egész oldalt – DOM, CSS, JavaScript lefutott, minden – egy láthatatlan fülön, amíg a linken lógott a kurzorod. Ez a Speculation Rules API, és van benne egy részlet, amit a legtöbben, akik használják, valószínűleg nem tudnak: az egyik hivatalos beállítási szint évekig gyakorlatilag semmit nem csinált a nevében foglaltakból.

Diagram: böngészőablak egy linkre mutató kurzorral, mellette áttetsző, szaggatott vonallal összekötött szellem-ablak, amely a láthatatlanul előre renderelt oldalt jelképezi, jobbra pedig egy lezárt lakattal blokkolt változat egy érzékeny végpont felé

Prefetch vs. prerender: nem ugyanaz a súlyosztály

A Speculation Rules API egy <script type="speculationrules"> blokkal deklarált JSON szabályhalmaz, ami megmondja a böngészőnek, mely URL-eket érdemes előre betölteni. Két módja van, és a különbség nem apróság:

  • prefetch: csak a HTML választ tölti le, a memóriában tartott dokumentum-cache-be teszi. Olcsó, de a kép, CSS, JS csak kattintás után jön.
  • prerender: teljes navigációt hajt végre – aloldalak, JS lefut, a DOM felépül – egy inaktív, láthatatlan fülön. Aktiváláskor a böngésző csak átkapcsol rá, ez már-már azonnali élmény.

Az MDN dokumentációja egyenesen azt írja, hogy egy prerender erőforrásigénye nagyjából megegyezik egy <iframe> renderelésével. Ez a valódi ára az „instant” navigációnak: nem trükk, hanem tényleges duplikált munka a felhasználó gépén.

<script type="speculationrules">
{
  "prerender": [{
    "where": { "href_matches": "/termek/*" },
    "eagerness": "moderate"
  }]
}
</script>

Ez a szabály minden /termek/* linket prerenderel, amint a felhasználó „eléggé” érdeklődik iránta. De mit jelent pontosan a moderate?

Az eagerness szint, ami évekig nem csinált semmit

Négy eagerness érték létezik, ami azt szabályozza, mikor induljon el a spekulatív betöltés – a Chrome dokumentációja szerint:

  • immediate – amint a böngésző meglátja a szabályt, indul is.
  • eager – asztali gépen 10 ezredmásodperc hover után.
  • moderate – 200 ezredmásodperc hover, vagy pointerdown, amelyik előbb jön.
  • conservative – csak tényleges pointer/touch down eseményre.

Na, ezt valószínűleg nem tudtad: az eager szint a fenti 10 ezredmásodperces viselkedést csak 2025 decembere, a Chrome 143 óta tudja. Előtte szó szerint ugyanazt csinálta, mint az immediate – vagyis a négy szintből évekig gyakorlatilag csak három működött különbözőképpen, a negyedik egy alias volt. Aki a specifikáció alapján eager-t választott egy „finomabb, de még mindig proaktív” köztes megoldásnak, valójában a legagresszívabb, azonnali betöltést kapta – csak nem tudott róla, mert a dokumentáció a névre hivatkozva mást ígért, mint amit a motor ténylegesen csinált. A Chrome csapata ezt a saját dokumentációjában is elismeri: a mobilos heurisztika ráadásul csak 2026 januárja óta épül a viewportba kerülésre, tehát ez a sarok az API-nak még mindig aktívan mozog.

Ez nem csak kuriózum. Ha egy csapat eager-t állított be egy közepes forgalmú oldalon abban a hitben, hogy az „csak egy kicsit proaktívabb” a moderate-nál, valójában minden egyes linkre azonnal elindította a teljes prerendert, amint a szabály betöltődött – ami pontosan az a túlköltekezés, amit a négy szintes rendszer elméletileg elkerülni hivatott.

A böngésző korlátokkal védi magát tőled

Mivel a spekulatív betöltés pazarlásra hajlamos – a legtöbb hover sosem lesz kattintás –, a Chrome kemény felső korlátokat szab:

  • immediate eagerness-nél: legfeljebb 50 egyidejű prefetch, illetve 10 egyidejű prerender.
  • eager/moderate/conservative-nál: mindössze 2-2, FIFO sorrendben – az új interakció kilöki a legrégebbi spekulációt.

A FIFO-limit oka egyszerű: interakcióhoz kötött spekulációból nincs értelme sokat egyszerre tartani, mert a felhasználó úgyis csak egy linkre fog kattintani. A kilökött spekuláció viszont nem vész kárba – a HTTP-cache-be már bekerült erőforrásokat egy újbóli hoverelés újra felhasználja.

A veszélyes eset: amikor a mellékhatás nem várhat kattintásra

Egy prerenderelt oldal JavaScriptje ténylegesen lefut – beleértve az analytics hívásokat, hirdetési pixel-eket, vagy akár egy useEffect-be rejtett API-hívást. Ha ez nélkül fut le, hogy a felhasználó valaha ránézett volna az oldalra, hamis analytics-adatot, dupla konverziót vagy – rosszabb esetben – tényleges mellékhatást (kijelentkezés, kosárba tétel) generálhat pusztán egy hover miatt.

Erre két védelmi vonal van. A szerver oldali: minden spekulatív kérés egy Sec-Purpose fejlécet kap (prefetch, illetve prerendernél prefetch;prerender), amire a szerver akár 204-es válasszal is reagálhat – ez konkrétan letiltja a prerendert (de a prefetchet nem). Kipróbáltam helyben, node:http-vel:

const http = require('node:http');

const server = http.createServer((req, res) => {
  const secPurpose = req.headers['sec-purpose'] || '';
  const isPrerenderRequest = secPurpose.includes('prerender');

  if (req.url === '/checkout' && isPrerenderRequest) {
    // 204/205: letiltja a prerendert, a prefetchet nem
    res.writeHead(204);
    res.end();
    return;
  }

  res.writeHead(200, { 'content-type': 'text/plain' });
  res.end(`OK: ${req.url}`);
});

server.listen(4321);

Valódi kéréssel tesztelve: egy sima navigáció a /checkout-ra 200-at kap, egy szimulált prerender-kérés (Sec-Purpose: prefetch;prerender fejléccel) pedig 204-et – tehát a Chrome ezen az úton sosem fogja láthatatlanul megrenderelni a fizetési oldalt.

A kliens oldali védelem a document.prerendering property és a prerenderingchange esemény: ezekkel elhalasztható minden olyan JS-mellékhatás, aminek csak tényleges megtekintéskor szabadna lefutnia.

function initAnalytics() {
  analytics.trackPageview(location.pathname);
}

if (document.prerendering) {
  document.addEventListener('prerenderingchange', initAnalytics, { once: true });
} else {
  initAnalytics();
}

A specifikáció emellett eleve több tucat API-t automatikusan felfüggeszt prerender alatt (geolokáció, értesítések, Web Audio, service worker regisztráció), és a cross-origin navigáció, a nem-HTTP séma (javascript:, data:) vagy a window.alert() egyszerűen nem működik – utóbbi némán no-op lesz.

Ki hajlandó ezt egyáltalán futtatni

Itt jön a hidegzuhany: a document.prerendering és az egész prerender-mechanizmus jelenleg kizárólag Chromium-alapú böngészőkben létezik. Az MDN böngészőtámogatási adatai szerint sem a Firefox, sem a Safari nem támogatja – a support tábla mindkettőnél kifejezetten false. A specifikáció maga is a WICG nav-speculation repóban él, tehát még nem jutott el a W3C/WHATWG szintű standardizációig.

Ami különösen érdekes: a Mozilla hivatalos állásfoglalása a puszta prefetchre pozitív – azt tervezik felvinni a HTML specifikációba –, de magára a prerenderre semleges marad, és ezt konkrét indokkal: szerintük „hatalmas komplexitási költséggel jár, nem csak a motoron belül, hanem az összes többi webes API-ra és felhasználói library-ra nézve is”, mivel a prerender lényegéhez tartozik, hogy a teljes oldal ténylegesen lefusson egy speciális, minden más API viselkedését módosító állapotban. A WebKit ugyanerről szóló egyeztetése (standards-positions #54) pedig évek óta nyitva áll, hivatalos állásfoglalás nélkül.

Ez azt jelenti, hogy amit beállítasz, az minden más böngészőben egyszerűen figyelmen kívül marad – nincs hibaüzenet, nincs törés, csak nem történik semmi. Ettől progresszív fejlesztésre tökéletesen alkalmas: a <script type="speculationrules"> blokk a nem támogató böngészőkben egy inert script tag, ami nem árt, csak nem gyorsít.

Használnám-e productionben?

Prefetchre: igen, gond nélkül, szinte bármilyen tartalmi oldalon (blog, dokumentáció, katalógus) – a kockázat alacsony, a nyereség valós, és ha nem támogatja a böngésző, semmi nem romlik el.

Prerenderre viszont csak megfontoltan. A moderate vagy conservative eagerness ésszerű alapértelmezés – az immediate egy közepes forgalmú oldalon simán szétlövi a FIFO-limitet és feleslegesen renderel oldalakat, amikre soha nem kattint senki. Az eager-t csak akkor válaszd tudatosan, ha tényleg azt akarod, hogy 10 ezredmásodperc hoverre azonnal induljon a teljes render – ma már ez a valós viselkedése, nem csak papíron. És mielőtt bárhová bevezeted: nézd át, mi fut le a célszűrőn kívül eső, minden oldalon jelen lévő scriptekben (analytics, A/B teszt, hirdetés), mert ezek prerender alatt is lefutnak, ha nem védtétek le őket document.prerendering-gel.

A legnagyobb kompromisszum végül nem is technikai, hanem stratégiai: amíg a Firefox és a Safari kimarad, a prerender legfeljebb a felhasználóid egy részének ad instant navigációt, a többinek pontosan ugyanaz marad, ami eddig volt. Ez nem hátrány – csak azt jelenti, hogy a teljesítménybüdzsédet nem szabad erre az egy API-ra építeni, hanem kiegészítésként érdemes rátenni egy amúgy is gyors oldalra.

Források

Leave a Reply

Az e-mail címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük