Pro kodéry: IntersectionObserver a snadné sledování, zda prvek naroloval do viditelné části

Už mnohokrát jsem řešil potřebu nějaké reakce webové stránky poté, co ji uživatel naroluje tak, že je vidět konkrétní prvek. S IntersectionObserver API je to hračka, a navíc vám i sdělí, jaké procento daného prvku už je v narolované stránce vidět.

Reklama

Nejčastěji mám požadavek na animace. Prostě, když uživatel posune webovou stránku do určité části tak, že začne být vidět nějaký prvek, nechť se začne animovat. Nebo: když někdo naroluje stránku tam a tam, ať se někde něco rozsvítí. Příkladů ze své praxe byste jistě našli několik.

Já to doposud řešil tak, že jsem pracoval s resize a scroll událostí a velikostmi prvků, které mě zajímaly a s funkcí getBoundingClientRect(). Podle všeho nejsem sám. Nicméně vždycky mi to přišlo takové neohrabané.

Loni v dubnu implementoval Chrome IntersectionObserver API, nyní s tím přichází i Firefox od verze 55. Podle Caniuse umí IntersectionObserver API také Edge 15, Opera a mobilní prohlížeče pro Android. Safari, včetně mobilního to, zdá se, ignoruje, stejně jako vývojáři polomrtvého Internet Exploreru.

Co vlastně IntersectionObserver API dělá? Ve zkratce řečeno, vytvoříte nového pozorovatele (observer), přiřadíte mu prvek, který chcete sledovat, a pak jen počkáte, až pozorovatel spustí nějakou akci. Stačí vám na to dva řádky kódu v JavaScriptu a pak samozřejmě kód obsluhující událost, která má nastat při narolování prvku do viditelné oblasti stránky.

Jak použít IntersectionObserver API

Řekněme, že tedy máte dlouhatánskou stránku, kterou uživatel roluje a poté, co se na ní objeví nějaký prvek, má se spustit jeho animace.

Zápis by byl následující:

let observer = new IntersectionObserver(handler);
observer.observe(document.getElementById("prvek"));

Samozřejmě si musíte definovat i onen handler, tedy obsluhu události, kdy pozorovatel zjistí, že prvek se naroloval do viditelné oblasti.

function handler(entries, observer) {
  for (entry of entries) {
    statusText.textContent = entry.isIntersecting;
    if (entry.isIntersecting) {
      document.getElementById("prvek").classList.add('shake');
    } else {
      document.getElementById("prvek").classList.remove('shake');
    }
  }
}

Handler má dva argumenty. První obsahuje záznamy o události, druhý je vytvořený observer. Pomocí entry.isIntersecting vracející true či false zjistíte, zda se sledovaný prvek právě nachází ve viditelné části stránky a podle toho můžete zareagovat. Následující moje ukázka v takovém případě přidá nebo odebere CSS třídu spouštějící animaci prvku.

Klepněte si prosím nahoře odkaz Edit in JSFiddle„ zde se vložený kód bohužel natáhne na výšku stránky a tím pádem na ní není co v praxi předvést.

Poznámka: v demoukázce používám pro rychlé zformátování Bootstrap a animační framework Animate.css. Vřele jej doporučuji vyzkoušet.

Jak velká část prvku je už/ještě viditelná?

Výše uvedená ukázka může mít v praxi v některých situacích problém s tím, že se handler spustí prakticky ihned, jakmile je alespoň část sledovaného prvku už viditelná. Vytvoření observeru je možné upravit tak, že změníte výchozí nastavení, aby reagoval až poté, co je sledovaný prvek vidět celý:

let observer = new IntersectionObserver(handler, {threshold: 1 });

Případně můžete pracovat s tím, že chcete zareagovat pro zobrazení alespoň určitého procenta plochy prvku, třeba jeho poloviny:

let observer = new IntersectionObserver(handler, {threshold: 0.5 });

Uvedete-li jako hodnotu treshold nulu, nastavíte tak výchozí stav, kdy observer řekne handleru v entry.isIntersecting hodnotu true až poté, co je prvek vidět celý. V handleru jste navíc schopni pracovat s hodnotou entry.intersectionRatio, udávající procento zobrazené části sledovaného prvku.

Kromě tresholdu je možné v poli druhého argumentu uvést také kořenový prvek, pokud nechcete sledovat posun celé stránky. A také rootMargin pro nastavení okrajů. Čili nějak takto:

let observer = new IntersectionObserver(handler, {threshold: 0.5, root: document.querySelector('#container'), rootMargin: "10px" });

Polyfill pro prohlížeče bez podpory

Jistě vás teď napadne, jak je to spolehlivé, když některé webové prohlížeče a některé starší verze IntersectionObserver API nepodporují. Řešením je samozřejmě polyfill.

V praxi jej můžete vyzkoušet třeba v době vydání tohoto článku aktuálním Firefoxu 54, který ještě IntersectionObserver API nepodporuje. Ve výše uvedeném demu mám doplněný polyfill a pokud jej odstraníte, pak ve FF54 a starším nebude ukázka fungovat.

Další příklady

Nějaké další povídání o IntersectionObserver API včetně ukázek najdete v článku Dana Callahana na webu Mozilla Hacks, případně v dokumentaci.

Reklama

Komentáře

I přesto, že je v ukázce polyfill (jak je v textu psáno), v Safari (9.1.3) ukázka nefunguje.
Reálná/praktická použitelnost je podle mne důležitá. A skóre implementovanosti kolem 50% je zatím málo.

Chce to jiný polyfill, řekl bych. Možná https://www.npmjs.com/package/intersection-observer-polyfill nebo https://github.com/jeremenichelli/intersection-observer-polyfill Nemám možnost to nyní na Safari vyzkoušet, ale Google vám jich najde celou řadu.

Tvořím weby. Nabízím poradenství pro Drupal. Jsem na Twitteru.

Přidat komentář