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.

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.

Buďme ve spojení, přihlaste se k newsletteru

Odesláním formuláře souhlasíte s podmínkami zpracováním osobních údajů. 
Více informací v Ochrana osobních údajů.

Autor článku: Jan Polzer

Tvůrce webů z Brna se specializací na Drupal, WordPress a Symfony. Acquia Certified Developer & Site Builder. Autor několika knih o Drupalu.
Web Development Director v Lesensky.cz. Ve volných chvílích podnikám výlety na souši i po vodě. Více se dozvíte na polzer.cz a mém LinkedIn profilu.

Komentáře k článku

návštěvník

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.

Přidat komentář

Odesláním komentáře souhlasíte s podmínkami Ochrany osobních údajů

reklama
Moje kniha o CMS Drupal

 

Kniha 333 tipů a triků pro Drupal 9


Více na KnihyPolzer.cz

Sledujte Maxiorla na Facebooku

Maxiorel na Facebooku

Hosting pro Drupal a WordPress

Hledáte český webhosting vhodný nejenom pro redakční systém Drupal? Tak vyzkoušejte Webhosting C4 za 1200 Kč na rok s doménou v ceně, 20 GB prostoru a automatické navyšováním o 2 GB každý rok. Podrobnosti zde.

@maxiorel na Twitteru

Maxiorel na Twitteru