Martin Michálek Martin Michálek  – 26. 5. 2020

Preload je deklarace, které vyvolává dřívější stažení prvku stránky a v případě JavaScriptu odděluje stažení od spuštění.

Vezměme jednoduchý příklad s webfonty. Můžeme jich v CSS mít nalinkováno více. Dva konkrétní soubory včak chceme stáhnout s vyšší prioritou. Uděláme to takhle:

<link rel="preload" href="font-1.woff2"
  as="font" type="font/woff2" crossorigin>
<link rel="preload" href="font-1.woff2"
  as="font" type="font/woff2" crossorigin>

Prohlížeč těmto dvěma souborům zvýší prioritu stažení. Ve vodopádu průběhu stahování prvků ze stránky to bude vypadat jako na následujícím obrázku.

Díky tomuto triku pak dojde k rychlejšímu zobrazení písem ve správném fontu na důležitých místech stránky. Například následovně:

O čem se v článku budeme bavit?

Obsah

Preload se občas zaměňuje s jinou užitečnou meta značkou <link rel="preconnect">. O té ale píšeme na jiném místě.

Související: Preconnect a dns-prefetch: Přednavázání spojení

Preload je užitečná pokročilá technika, kterou podporují všechny prohlížeče kromě (zatím ještě) Firefoxu a (bohužel už napořád) Internet Exploreru. Dejme ale důraz na slovo pokročilá.

Opatrně s tím

Ve zkušených rukou může být preload silná zbraň věc. Raději ale upozorním na to, že jako v mnoha jiných případech je to dobrý sluha, ale zlý pán.

Dokud si nejste zcela jistí, co děláte, s preloadem si raději nehrajte. Ono totiž porušení přirozeného vodopádu stahování frontendových souborů může být ke škodě.

Už na prvním obrázku je například jedna nevýhoda vidět – díky tomu, že se soubory přednačtených fontů stahují souběžně s CSS, oddálí zpracování stylů a tím také první vykreslení stránky.

Stále častěji totiž potkávám weby, kde byla aplikována tzv. Babicova přednačítací metoda: „Když už nevíš, co s tím, dej tam preload.“ Opatrně s tím.

V detekci zbytečných preloadů může pomoci sledování konzole prohlížeče. Chrome totiž hlásí nevyužité přednačtení:

The resource (…) was preloaded using link preload but not used within a few seconds from the window's load event. Please make sure it wasn't preloaded for nothing.

Tato informativní hláška se zobrazí zhruba 3 vteřiny po události Load. U takto označených zdrojů je pravděpodobné, že jde o zbytečný <link rel="preload">.

Atribut as – určení prioritizace

Tento nepovinný atribut vám doporučuji k preload přidávat vždy. Pomohou prohlížeči určit, o jaký prvek se jedná.

Přednačtené prvky stránky používající atribut as totiž budou mít stejnou prioritu jako typ zdroje, který je uvedený v hodnotě.

Například preload as="style" získá nejvyšší prioritu, zatímco as="script" získá nízkou nebo střední prioritu. Tyto prvky pak také podléhají stejným zásadám Content Security Policy (CSP) a do prohlížeče dorazí se správnou hlavičkou Accept.

Možných hodnot atributu as je celá řada. Vybírám zde ty nejvíce použitelné:

Hodnota Typ souboru
audio Audio, typicky v prvku <audio>.
document HTML dokument, typicky <frame> nebo <iframe> (bug v Chrome).
embed Prvek <embed>.
fetch Prvek, který použijeme pomocí fetch nebo XHR, např. JSON soubor.
font Soubor s fontem, např. WOFF2.
image Obrázek.
object Prvek <object>.
script Soubor s JavaScriptem.
style CSS soubor.
worker Soubor s javascriptovým web workerem.
video Video soubor, typicky v prvku <video>.

Všechny možné hodnoty atributu as jsou ve specifikaci.

Atribut type - mime type

Nepovinný atribut, který umožní prohlížeči zvážit, zda daný typ prvku podporuje a tedy zda jej chce stahovat nebo ne.

Vezměme příklad:

<link rel="preload" href="video.webm"
  as="video" type="video/webm">

Soubor video.webm přednačtou díky atributu type="video/webm" pouze prohlížeče, které formát WEBM zvládají, tedy všechny kromě Exploreru a Safari.

Atribut crossorigin – pravidla pro CORS, u webfontů nutné

Pokud máte na webu nastaveno Cross-Origin Resource Sharing (CORS), můžete u <link rel="preload"> uvést atribut crossorigin. Toto platí hlavně pro případy, kdy stahujete prvky z jiné domény než je ta, odkud se stahuje dokument.

V případě přednačtení webfontů ale platí, že byste tento atribut měli uvádět vždy – i když jsou soubory stahované ze stejné domény. Pokud byste crossorigin neuvedli, stáhnou se soubory s fonty dvakrát. Takže fonty vždy přednačítejte takto:

<link rel="preload" href="font-1.woff2"
  as="font" type="font/woff2" crossorigin>

Atribut media - Media Queries

Může se vám stát, že některý soubor potřebujete přednačíst jen v určitém responzivním (nebo klidně jiném) kontextu Media Queries. Pak neváhejte využít volitený atribut media:

<link rel="preload" as="image" href="obrazek.jpg"
  media="(min-width: 640px)">

Zde můžeme ukončit téma atributů a podívat se úplně jinam. Vlastně úplně mimo HTML.

HTTP hlavička

Občas se hodí přidávat informace o dokumentu už rovnou na backendu, bez nutnosti zásahu do HTML. Je tudíž dobré vědět, že v do HTTP hlavičky se toho vejde…

Následuje bambilión různých příkladů:

Link: <https://example.com/font.woff2>; rel=preload; as=font; type="font/woff2"
Link: <https://example.com/app/script.js>; rel=preload; as=script
Link: <https://example.com/logo-hires.jpg>; rel=preload; as=image
Link: <https://fonts.example.com/font.woff2>; rel=preload; as=font; crossorigin; type="font/woff2"

JavaScriptem a dynamicky

Jestliže se vám zachtělo přidávat <link rel="preload"> naopak až při zpracování stránky na frontendu, JavaScriptem, možnosti tady jsou:

<script>
  var res = document.createElement("link");
  res.rel = "preload";
  res.as = "style";
  res.href = "main.css";
  document.head.appendChild(res);
</script>

Uvedený kód do DOMu přidá následující:

<link rel="preload" href="main.css" as="style">

Ptáte-li se, k čemu by vám bylo přednačtení vkládáné dynamicky až javascriptem, pak si uvědomme, že preload vždy vyvolává stažení souboru a je mu v zásadě jedno, kdy to udělá.

Detekce podpory

Když už jsme u JS, mohla by se vám také hodit detekce podpory <link rel="preload">

var preloadSupported = function() {
  var link = document.createElement('link');
  var relList = link.relList;
  if (!relList || !relList.supports)
    return false;
  return relList.supports('preload');
}

…čímž se dostáváme k tématu podpory v prohlížečích.

Podpora v prohlížečích

Kromě Exploreru zatím podle CanIUse přednačtení nepodporuje Firefox. Podle Bugzilly vlastně trochu podporuje, ale nechávají to skryté za vlaječkovým nastavením. Michal Špaček ale objevil, že se to ale brzy může změnit a na preload se můžeme těšit i ve Firefoxu.

Nemělo by to vadit, protože hrátky s přednačtením považuji za klasických příklad progressive enhancement, dobrovolného vylepšení uživatelského prožitku.

Možné scénáře použití

Vybral jsem pár konkrétních příkladů, kdy se <link rel="preload"> může hodit. Jen tak, pro inspiraci.

Přednačtení kritických fontů

O použití pro potřeby zrychlení webových fontů se v článku několikrát otíráme:

<link rel="preload" href="font-1.woff2"
  as="font" type="font/woff2" crossorigin>
<link rel="preload" href="font-2.woff2"
  as="font" type="font/woff2" crossorigin>

Je ale dobré ještě jednou zdůraznit, že se tímto soubory s webfonty dostanou prioritou stahování ještě před naše CSS a zpozdí nám tím mírně metriku FCP.

Proto bychom takto neměli zvýhodňovat všechny řezy webfontů, ale jen ty opravdu podstatné právě pro první vykreslení stránky.

Zvýšení priority obrázku z CSS

Vezměme, že v hlavičce stránky máme obrázek. Ten je ale vložený v CSS na pozadí prvku:

.hero {
  background-image: url(hero.jpg);
}

Je asi přirozené takto podobný typ obrázků vkládat, ale ve frontě stahování dostane nízkou prioritu. Pokud bychom obrázku chtěli pomoci k dřívějšímu zobrazení, zvážíme preload:

<link rel="preload" href="hero.jpg" as="image">

Zvýšení priority asynchronního JS

Tento způsob vložení JavaScriptu do HTML určitě znáte:

<script src="script.js" async></script>

Je výhodný pro méně důležité a samostatně fungující prvky stránky, protože neblokuje první vykreslení. Jenže tento soubor se pak stáhne a kód uvnitř provádí s velmi nízkou prioritou.

Pokud bychom prioritu chtěli zvýšit, uděláme to právě pomocí přednačtení:

<link rel="preload" href="script.js" as="script">

Web Treebo takto vykreslovací metriky zlepšil o 1 vteřinu. Píše to Addy Osmani ve svém textu Preload, Prefetch And Priorities in Chrome.

Asynchronní stažení CSS

Občas se může hodit soubory se styly načítat asynchronně, například při nějaké vlastní implementaci kritického CSS.

Preload tuto vlastnost nabízí díky tomuto elegantnímu triku:

<link rel="preload" href="style.css"
  onload="this.rel=stylesheet”>

Spuštění JS definované vývojářem, nikoliv prohlížečem

Další hezký příklad využití jsem našel ve specifikaci:

<script>
  function preloadFinished(e) { ... }
</script>

<link rel="preload" href="app.js"
  as="script" onload="preloadFinished()">

V tomto případě je spuštění nějakého kódu navázáno na dokončení stahování (onload). Spouštět však můžeme, kdykoliv si sami definujeme. Nemusíme prostě nechat čas spuštění přednačteného JavaScriptu na prohlížeči.

Stažení i spouštění JS na míru

Když půjdeme ještě dál, můžeme si zevnitř javascriptového kódu řídit moment stažení i spuštění libovolného souboru s JS. Navrhuje to Yoav Weiss:

function downloadScript(src) {
  var el = document.createElement("link");
  el.as = "script";
  el.rel = "preload";
  el.href = src;
  document.body.appendChild(el);
}
function runScript(src) {
  var el = document.createElement("script");
  el.src = src;
}

Vysvětlení je prosté:

  • Funkce downloadScript() do DOMu přidá <link rel="preload"> a tudíž vyvolá stažení prvku.
  • Funkce runScript() do DOMu přidá prvek <script> a tedy vyvolá spuštění skriptu.

Tím jsme vyčerpal své vědomosti o <link rel="preload">. Budu rád za každý váš tip, trik nebo připomínku v komentářích.

Preload může být výborná věc k doladění rychlosti vašeho webu, ale jak už jsem napsal – nepoužívejte jej bezhlavě a dobře testujte své experimenty.