Moderní tvorba webových aplikací

O webu

SPA přístup pro obsahové weby

Jak vytvořit obsahový web s dynamickým načítání obsahu bez obnovení celé stránky.

10 minut

Pro zlepšení uživatelského dojmu z webu může posloužit moderní přístup k načítání obsahu bez obnovení celé stránky.

Díky dynamickému načítání obsahu může být přechod mezi stránkami rychlejší a plynulejší.

  1. Stačí přenášet jen obsah, který se mění.
  2. Překreslovat se bude jen část stránky, která se změnila. Namísto kompletního vykreslení stránky od nuly.

Na prvním bodu většinou ani moc nezáleží – velikost výsledných HTML kódů se obvykle pohybují v desítkách kilobytů, což příliš velký prostor pro úsporu nepřináší. Překreslování jen změněné části ale většinou velmi znatelně přechod po webu zrychlí.

Jak na to

Dříve se tato metoda nazývala jako AJAX (ajaxová stránka apod.), někdy také jako PJAX (pushState + AJAX). Dnes se tomu říká nejčastěji SPA – single page aplikace.

Nicméně nic nebrání udělat celý obsahový web ve stylu SPA.

Fetch API

Nativní JavaScript API, které nahradilo starý XMLHttpRequest. Umožňuje čistou práci s HTTP požadavky pomocí Promise objektů a async/await syntaxe.

History API

Zásadní věc je podpora změny URL JavaScriptem pomocí history.pushState – dnes je to podporováno všemi moderními prohlížeči včetně mobilních.

To umožní i při obsloužení změny obsahu dynamicky změnit URL do podoby, která se může načíst i bez JS. Bez této funkce bych se do obsahového webu s dynamickým načítáním nepouštěl.

SPA vs. SSR přístup

Dnešní weby často používají hybridní přístup - Server-Side Rendering pro první načtení a Client-Side Routing pro další navigaci. To kombinuje výhody rychlého prvního načtení s plynulou navigací.

Signalisace načítání

Je dobré znázornit, že se po kliknutí na odkaz něco děje. Při klasickém přecházení mezi stránkami to automaticky řeší prohlížeč. Při dynamické změně obsahu to musíme řešit vlastní signalisací.

Znázorňovat načítání nemusí být dobré ihned po kliknutí. Pokud web funguje normálně, mělo by načtení obsahu být tak rychlé (desítky až nízké stovky milisekund), že by znázornění načítání stejně jen probliklo.

Uživatelé bývají zvyklí, že se po kliknutí na odkaz chvíli nic neděje, nabízí se tedy načítání znázorňovat třeba až 0,5 vteřiny od vyvolání akce.

Moderní přístupy používají skeleton loadery nebo progressive enhancement pro lepší UX.

Přednačítání a optimalisace

Zrychlit dojem z webu může ještě přednačítání. Celý proces změny obsahu rozložíme do dvou kroků.

  1. stažení/zpracování obsahu,
  2. zobrazení obsahu

Má to svoje výhody i nevýhody. Umožní to rychlejší změnu obsahu, ale může plýtvat daty (načte se něco, co uživatel nakonec nebude chtít zobrazit).

Rozumné může být přednačtení při najetí myší (onmouseover) nebo stisknutí tlačítka (onmousedown). Zvlášť při stisknutí tlačítka myši nad odkazem je vysoká šance, že uživatel dokončí kliknutí (neodjede myší pryč) a můžeme tak získat třeba 100 milisekund, které běžné kliknutí trvá (stisknutí a uvolnění tlačítka). Tedy v době dokončení kliknutí už mít načteno.

Moderní prohlížeče také podporují Intersection Observer API, které umožňuje efektivněji detekovat, kdy se odkazy dostanou do viewportu a případně je přednačítat.

Hotová řešení

Dnešní populární JS frameworky toto chování podporují, aniž by se autor webu musel nějak snažit.

  • Next.js – React framework s hybridním SSR/SPA přístupem
  • Nuxt.js – Vue.js framework s podobnými možnostmi
  • SvelteKit – moderní Svelte framework s univerzálním renderingem

Implementace v JavaScriptu

Zde je příklad, jak implementovat dynamické načítání obsahu pomocí Fetch API.

Minimální implementace v čistém JS může vypadat následovně:

async function loadContent(url) {
  try {
    // Načtení HTML obsahu z URL pomocí Fetch API
    const response = await fetch(url);
    // Extrakce textového obsahu z response
    const html = await response.text();
    
    // Vložení načteného HTML do elementu s ID 'content'
    document.getElementById('content').innerHTML = html;
    // Aktualizace URL v prohlížeči bez obnovení stránky
    history.pushState({}, '', url);
  } catch (error) {
    // Ošetření chyby při načítání
    console.error('Chyba při načítání obsahu:', error);
  }
}

// Poslouchání kliknutí na všechny odkazy
document.addEventListener('click', (e) => {
  // Kontrola, zda kliknutý element je odkaz začínající na "/"
  if (e.target.matches('a[href^="/"]')) {
    // Zabránění výchozímu chování (obnovení stránky)
    e.preventDefault();
    // Volání funkce pro načtení obsahu
    loadContent(e.target.href);
  }
});

Co je potřeba vyřešit pro reálnou implementaci

Výše uvedený kód je pouze základní ukázkou. Pro produkční nasazení je potřeba vyřešit:

  • Titulek stránky – měnit <title> webu, mít správné meta tagy, Open Graph, strukturovaná data
  • Tlačítka vpřed/zpět – obsluha navigace v prohlížeči
  • Připojování/odpojování JS – pokud stránky používají JS, musí se řešit init a destroy po změně navigace
  • Odesílání formulářů – další věc je odesílání formulářů JavaScriptem
  • Loading stavy – indikátory načítání, skeleton loadery
  • Error handling – mít nějaký fallback při selhání načítání
  • Analytické nástroje – sledování page views a uživatelského chování funguje u SPA trochu jinak

Proto se v praxi často používají osvědčené frameworky jako Next.js, Nuxt.js nebo SvelteKit, které tyto problémy řeší out-of-the-box.

Nevýhody SPA přístupu

I když má SPA přístup mnoho výhod, má také své nevýhody, které je potřeba zvážit:

Zvýšená komplexita

Implementace SPA funkcionality vyžaduje řešení mnoha problémů, které klasické weby řeší automaticky:

  • State management – správa stavu aplikace mezi navigacemi
  • Memory leaks – risiko úniku paměti při nesprávném odstraňování event listenerů
  • Event handling – správné připojování/odpojování JavaScript funkcí
  • Form handling – odesílání formulářů bez obnovení stránky

Každá chyba může být fatální.

Výhoda klasického přístupu je, že i když web používá JavaScript, každá změna navigace reálně znamená restart aplikace. SPA může hnít v prohlížeči klidně měsíce.

Výkon

SPA přístup má své nevýhody i v oblasti výkonu – zejména první načtení, které je pomalejší kvůli stahování obslužného JS.

Přístupnost

Docílit dobré přístupnosti může být v SPA složitější:

  • Čtečky obrazovky – mohou mít problémy s dynamicky měnícím se obsahem
  • Ovládání klávesnicí – focus management je složitější

Složitější debugging

Vývoj a údržba SPA může být náročnější, protože mohou existovat chyby, které se projeví třeba až při načtení více stránek v určitém pořadí, což se špatně odhaluje, popisuje a reprodukuje.

Závěr

Doporučuji pečlivě zvážit, zda SPA přístup skutečně přináší hodnotu pro konkrétní projekt, nebo zda není lepší zůstat u klasického server-side renderingu.

Zajímavým příkladem je třeba Astro, které schválně používá plnohodnotnou navigaci mezi stránkami. Pokud je web rychlý sám o sobě, těžko jde reálně poznat rozdíl.

Potřebnou JS funkcionalitu jde realizovat přes tzv. Islands architecture, kdy se na potřebná místa na stránce doplňují JS komponenty, které ale neblokují vykreslování hlavního obsahu.

Pro SPA chování na obsahové stránce bych tak hledal opravdu dobrý důvod. Kdy má tedy SPA přístup skutečně smysl? Napadají mě následující případy:

  1. Real-time funkcionalita – chat aplikace, live updates, notifikace, přehrávání videa nad samotnou stránkou – klasická změna navigace by přerušila zážitek
  2. Zabudované ve frameworku – pokud SPA chování framework automaticky podporuje, asi není potřeba to za každou cenu vypínat

Klíčové je neřešit technické problémy, které neexistují. Pokud klasický web funguje dobře a uživatelé si nestěžují, není důvod přidávat složitost.

Související články

Detekce otevření DevTools

Jak zjistit, že se na stránce otevřely vývojářské nástroje.

13 minut

JavaScript null a undefined

Rozdíly mezi null a undefined v JavaScriptu, kdy je používat a jak se vyhnout běžným chybám.

12 minut

Sleep v JavaScriptu

Jak implementovat sleep/delay funkcionalitu v JavaScriptu pomocí Promise a async/await

6 minut

JavaScript Battery API

Jak v JS zjistit stav baterie, co dnes funguje a kdy API nepoužívat.

3 minuty

Web jecas.cz píše Bohumil Jahoda, kontakt
Seznam všech článků
2013–2025