6. března 2026

Rolování

Na rolování stránky nebo elementu nám umožňuje reagovat událost scroll. Můžeme s ní provádět některé opravdu pěkné věci.

Například:

  • Zobrazit nebo skrýt další ovládací prvky nebo informace podle toho, kde v dokumentu se uživatel nachází.
  • Načíst další data, když uživatel doroluje na konec stránky.

Následující malá funkce zobrazuje aktuální délku rolování:

window.addEventListener('scroll', function() {
  document.getElementById('ukažRolování').innerHTML = window.pageYOffset + 'px';
});

V akci:

Aktuální rolování = rolování okna

Událost scroll funguje dobře na window i na rolovatelných elementech.

Zákaz rolování

Jak zakážeme, aby něco mohlo být rolováno?

Nemůžeme zakázat rolování voláním událost.preventDefault() v posluchači onscroll, protože ten se spustí až poté, co k rolování skutečně dojde.

Můžeme však zakázat rolování voláním událost.preventDefault() na události, která rolování způsobila, například na události keydown pro pageUp a pageDown.

Jestliže přidáme handler k těmto událostem a v něm zavoláme událost.preventDefault(), rolování se nespustí.

Způsobů, jak vyvolat rolování, je mnoho, proto je spolehlivější použít vlastnost overflow v CSS.

Následuje několik úloh, které můžete vyřešit nebo se na ně podívat, abyste viděli, jak se onscroll aplikuje.

Úlohy

důležitost: 5

Vytvořte nekonečnou stránku. Když návštěvník doroluje na konec, automaticky připojí k textu aktuální datum a čas (takže návštěvník může rolovat dál).

Příklad:

Prosíme všimněte si dvou důležitých vlastností rolování:

  1. Rolování je „elastické“. Na některých prohlížečích nebo zařízeních můžeme rolovat kousek před začátek nebo za konec dokumentu (zobrazí se prázdné místo dole a pak dokument automaticky „poskočí“ do normálního stavu).
  2. Rolování je nepřesné. Když dorolujeme na konec stránky, můžeme být ve skutečnosti zhruba 0-50px od skutečného konce dokumentu.

„Dorolování na konec“ by tedy mělo znamenat, že návštěvník není více než 100px od konce dokumentu.

P.S. Ve skutečném životě bychom asi chtěli zobrazit „další zprávy“ nebo „další zboží“.

Otevřít pískoviště pro úlohu.

Jádrem řešení je funkce, která přidá na stránku další data (nebo v reálném životě načte další obsah), když jsme na konci stránky.

Můžeme ji okamžitě zavolat a přidat jako handler window.onscroll.

Nejdůležitější otázka zní: „Jak zjistíme, že stránka je odrolována na konec?“

Použijeme souřadnice relativní vzhledem k oknu.

Dokument je reprezentován (a obsažen) uvnitř značky <html>, což je document.documentElement.

Souřadnice celého dokumentu vzhledem k oknu můžeme získat voláním document.documentElement.getBoundingClientRect(), vlastnost bottom pak bude souřadnice dolního konce dokumentu vzhledem k oknu.

Pokud je například výška celého HTML dokumentu 2000px, pak:

// když jsme na vrchu stránky
// top vzhledem k oknu = 0
document.documentElement.getBoundingClientRect().top = 0

// bottom vzhledem k oknu = 2000
// dokument je dlouhý, takže to bude pravděpodobně daleko za dolním okrajem okna
document.documentElement.getBoundingClientRect().bottom = 2000

Pokud odrolujeme o 500px dolů, pak:

// vrch dokumentu je 500px nad oknem
document.documentElement.getBoundingClientRect().top = -500
// spodek dokumentu je o 500px blíž
document.documentElement.getBoundingClientRect().bottom = 1500

Když dorolujeme až na konec za předpokladu, že výška okna je 600px:

// vrch dokumentu je 1400px nad oknem
document.documentElement.getBoundingClientRect().top = -1400
// spodek dokumentu je 600px pod oknem
document.documentElement.getBoundingClientRect().bottom = 600

Prosíme všimněte si, že bottom nemůže být 0, protože spodek nikdy nedosáhne vrchu okna. Nejnižší možná hodnota souřadnice bottom je výška okna (předpokládáme, že je to 600), výš už rolovat nemůžeme.

Výšku okna můžeme získat jako document.documentElement.clientHeight.

V naší úloze potřebujeme vědět, kdy od ní není spodek dokumentu vzdálen více než 100px (tedy 600-700px, je-li výška 600).

Funkce je tedy následující:

function přidejDatum() {
  while(true) {
    // spodek dokumentu
    let spodekVzhledemKOknu = document.documentElement.getBoundingClientRect().bottom;

    // pokud uživatel nedoroloval dost daleko (>100px do konce)
    if (spodekVzhledemKOknu > document.documentElement.clientHeight + 100) break;

    // přidáme další data
    document.body.insertAdjacentHTML("beforeend", `<p>Date: ${new Date()}</p>`);
  }
}

Otevřít řešení na pískovišti.

důležitost: 5

Vytvořte tlačítko „na začátek“, které bude pomáhat s rolováním stránky.

Mělo by fungovat následovně:

  • Dokud není stránka odrolována nejméně o výšku okna, není vidět.
  • Když je stránka odrolována dolů nejméně o výšku okna, v levém horním rohu se zobrazí šipka nahoru. Pokud je stránka rolována zpět, zmizí.
  • Po kliknutí na šipku stránka odroluje nahoru na začátek.

Takto (levý horní roh, po rolování uvidíte):

Otevřít pískoviště pro úlohu.

důležitost: 4

Řekněme, že máme pomalého klienta a chceme ušetřit přenesená data.

Z tohoto důvodu jsme se rozhodli nezobrazovat obrázky hned, ale nahradit je dočasným obsahem, například:

<img src="placeholder.svg" width="128" height="128" data-src="real.jpg">

Na začátku jsou tedy všechny obrázky placeholder.svg. Když stránka doroluje na pozici, z níž uživatel může obrázek vidět, změníme src obrázku na hodnotu uvedenou v data-src, a tak se obrázek načte.

Následuje příklad v iframe:

Při rolování v něm uvidíte, že se obrázky načítají „na požádání“.

Požadavky:

  • Když se stránka načte, měly by se okamžitě před jakýmkoli rolováním načíst obrázky, které jsou vidět na obrazovce.
  • Některé obrázky mohou být obvyklé, bez data-src. Na ty by kód neměl sahat.
  • Když se obrázek načte, neměl by se při dalším rolování načítat znovu.

P.S. Pokud to dokážete, vytvořte pokročilejší řešení, které bude „přednahrávat“ obrázky, které jsou jednu stránku nad nebo pod aktuální pozicí.

P.P.S. Ošetřujte jen svislé rolování, ne vodorovné.

Otevřít pískoviště pro úlohu.

Handler onscroll by si měl zkontrolovat, které obrázky jsou vidět, a zobrazit je.

Chceme ho spustit i ve chvíli, kdy se stránka načte, abychom detekovali okamžitě viditelné obrázky a načetli je.

Kód by se měl spustit, až bude dokument načten, aby měl přístup k celému jeho obsahu.

Nebo jej umístíme na konec <body>:

// ...obsah stránky je výše...

function jeVidět(elem) {

  let souřadnice = elem.getBoundingClientRect();

  let výškaOkna = document.documentElement.clientHeight;

  // je vidět vrch elementu?
  let jeVidětVrch = souřadnice.top > 0 && souřadnice.top < výškaOkna;

  // je vidět spodek elementu?
  let jeVidětSpodek = souřadnice.bottom < výškaOkna && souřadnice.bottom > 0;

  return jeVidětVrch || jeVidětSpodek;
}

Funkce zobrazViditelné() použije kontrolu viditelnosti, implementovanou ve funkci jeVidět(), a načte viditelné obrázky:

function zobrazViditelné() {
  for (let obrázek of document.querySelectorAll('img')) {
    let skutečnýZdroj = obrázek.dataset.src;
    if (!skutečnýZdroj) continue;

    if (jeVidět(obrázek)) {
      obrázek.src = skutečnýZdroj;
      obrázek.dataset.src = '';
    }
  }
}

zobrazViditelné();
window.onscroll = zobrazViditelné;

P.S. Řešení obsahuje i variantu funkce jeVidět, která „přednahraje“ obrázky, které jsou o jednu stránku nad nebo pod aktuálním rolováním dokumentu.

Otevřít řešení na pískovišti.

Mapa tutoriálu

Komentáře

přečtěte si před komentováním…
  • Máte-li návrhy na zlepšení, vytvořte prosím issue na GitHubu nebo pull request místo komentáře.
  • Pokud v článku něčemu nerozumíte, napište prosím, čemu přesně a na kterém místě.
  • Pro vložení několika slov kódu použijte značku <code>, pro několik řádků je obalte značkou <pre>, pro více než 10 řádků vložte odkaz na pískoviště (plnkr, jsbin, codepen…)