Posun obsahu se zachytáváním

Když uživatel posouvá stránku, málokdy se mu povede, že posun skončí přesně na začátku odstavce nebo obrázku, což pak zhoršuje UX (dojem ze stránky). Do teď se podobné situace řešili pomocí javaskriptu, ale kombinace JS a skrolování většinou UX ještě zhorší.

Díky nové CSS specifikaci Scroll snap můžete tyto situace vyřešit automaticky jen pomocí CSS definice.

Nová specifikace je již podporována v prohlížečích založených na Webkit (tedy Chrome, Opera a Safari). Firefox momentálně podporuje starší zamítnutou specifikaci.

Typ přichycení

Základní vlastností, pomocí které určíte, že se daný prvek má skrolovat, je scroll-snap-type společně s overflow: scroll (nebo auto). Vlastnost očekává kombinaci dvou hodnot. První je jedna z XY a BOTH a určuje, ve kterém směru se má skrolovat (nebo zda v obou směrech), a druhá pak určuje, jestli se má posun na daném bodě zastavit přesně (mandatory) nebo jen přibližně (proximity):

article {
    overflow: hidden;
    overflow-y: auto;
    scroll-snap-type: Y proximity;
}
.gallery {
    overflow: hidden;
    overflow-x: scroll;
    scroll-snap-type: X mandatory;
}

Příklad říká, že svislý posun článku se má pokusit přiblížit nadefinovaným bodům přichycení (např. odstavce). Naopak horizontální posun obrázků (vedle sebe) se musí vždy přesně zastavit na požadovaném bodě.

Všimněte si, že typ uchycení vždy definujeme na kontejneru, který se posouvá!

Body uchycení

Když máte určený typ přichycení, musíme určit body, ke kterým se bude posun přichycovat.

Body přichycení nastavíme prvkům uvnitř kontejneru, který se posouvá pomocí vlastnosti scroll-snap-align:

article > p {
    scroll-snap-align: start;
}
.gallery > img {
    scroll-snap-align: center;
}
.gallery > img:last-child { 
    scroll-snap-align: end; 
}

Vlastnost scroll-snap-align má tři možné hodnoty, které určují, zda se u daného prvku posun zastaví u jeho začátku (start), prostředku (center) nebo konce (end). V příkladu si tedy všimněte, že u článku se posun zastaví vždy na začátku odstavce, zatímco u galerie se zastaví tak, aby byl obrázek vždy vycentrovaný. Výjimku máme u posledního obrázku galerie, kde se má posun zastavit tak, aby byl poslední obrázek zarovnaný ke konci galerie.

Pozor na nepřístupný obsah

Jakmile nadefinujete body zachycení, bude se jimi prohlížeč řídit a bude obsah posouvat mezi nimi. Pokud tedy např. určíte uchycení na začátky odstavců, ale budete mít v textu odstavec delší než je jedna obrazovka (např. u mobilního zařízení), nebude si moci uživatel posunou text tak, aby si přečetl konec odstavce (protože obsah přeskočí automaticky na další odstavec).

Body uchycení je potřeba používat s rozvahou a pouze tam, kde jsou nezbytně nutné pro vylepšení UX!

Pokud si nejste jisti, kombinujte je s CSS podmínkou @media (min-*) tak, aby se aplikovaly jen na dostatečně velkých zařízeních a monitorech.

 
@media (min-height: 400px) {
   /* na příliš nízkých displejích
      se nebudou odstavce přichytávat
      k okrajům obrazovky */
    article { 
        overflow: hidden; 
        overflow-y: auto; 
        scroll-snap-type: Y proximity; 
    }
}

Okraje

Tak, jako můžete u DIVů, odstavců apod. určit, jaké mají mít okraje (padding a margin), aby jejich obsah pěkně pasoval do stránky, můžete stejně určit okraje zachycení (tedy vzdálenost od okraje):

 
article { 
    scroll-padding: 2em; 
}

Tento příklad dává smysl pouze v kombinaci s předchozími příklady. U článku jsme nastavili, že posun se má zastavit přibližně na začátku odstavce. V kombinaci s vlastností scroll-padding pak říkáme, že ono přibližně je o 2 řádky výše než je skutečný začátek odstavce. V praxi to tedy znamená, že posun se zastaví tak, že z předchozího odstavce bude zobrazen zhruba 1 až 2 řádky a další odstavec bude tedy vidět vždy od začátku. Kdybychom padding neuvedly, ono přibližně by mohlo způsobit, že se posun zastaví uprostřed první řádky odstavce.

Padding posunu určujeme na kontejneru, který se posouvá!

Naopak pokud chcete nastavit pro každý prvek jiný posun, můžeme prvkům v kontejneru určit okraj posunu vlastností scroll-margin:

.gallery > img { 
    scroll-margin: 10px; 
}
.gallery > img:last-child { 
    scroll-margin: 0; 
} 

Pro galerii, kde se posun zarovnává na prostředek obrázků říkáme, že obrázek se má brát jako že je o 10 pixelů větší. Pokud by se tedy nevešel celý do stránky (viewport kontejneru), bude zarovnaný doleva a odsazený o 10px doprava. Druhé pravidlo pak říká, že poslední obrázek se má zarovnat přesně s koncem kontejneru.

Margin posunu vždy určujeme na prvcích uvnitř kontejneru!

Obě vlastnosti scroll-padding a scroll-margin se chovají stejně jako původní margin a padding a je tedy možno nadefinovat různé rozměry pro různé strany:

article {  /* okraj jen nahoře */
    scroll-padding: 0;
    scroll-padding-top: 2em;
}
.gallery {  /* okraj jen vlevo */
   scroll-margin: 0 0 0 10px;
} 

Javascript

Společně s CSS vlastnostmi přichází i JS API pro posun pomocí programu (resp. obě funkce již nějakou dobu existují, ale nyní podporují zachytávání).

Pokud chcete posunout kontejner na určitý prvek, použijte jeho funkci scrollIntoView(), která bere v úvahu nastavené body zachytávání a okraje (scroll-padding a scroll-margin):

<a href="#example"
   onclick=document.getElementById('example')
           .scrollIntoView(); return false;">
   Zobrazit příklad
</a>

Pozor na to, že funkce scrollIntoView() nemusí existovat. V tomto příkladu bude vše fungovat, protože pokud funkce neexistuje, JS se neprovede a odkaz bude fungovat postaru pomocí href. Ve složitějších skriptech ale budete muset kontrolovat, zda funkce existuje, a pokud ne, provést posun postaru pomocí scrollTop nebo scrollLeft.

Stejně funguje i funkce scrollTo(X, Y), která taktéž bere v úvahu nadefinované body přichycení:

//posune stránku na konec
// (s ohledem na přichycení tam,
//   kde to prohlížeč podporuje)
window.scrollTo(
    0, document.body.getBoundingClientRect().y
);

Funkce scrollIntoView() má několik parametrů (předávaných v objektu): parametr behavior (pozor, není tam „u“!) může mít hodnoty instant (provede skok bez animace) nebo smooth (plynule posune stránku pomocí animace). Výchozí hodnota je auto (podle vzdálenosti); parametry block a inline určují, kam se prvek zarovná. Hodnota block určuje zarovnání bloků (většinou nahoru nebo dolu) a inline zarovnání v řádce (tedy doleva a doprava). Hodnoty jsou start, center, end a nearest, kde start a end určuje zarovnání nahoru nebo dolu resp. doleva nebo doprava. Hodnota center určuje zarovnání prvku na střed prostoru a nearest zarovná prvek k bližšímu z okrajů. Výchozí hodnoty jsou block: center a inline: nearest.

Parametr behavior podporují pouze prohlížeče s podporou scroll-snap-align. Některé prohlížeče nepodporují hodnoty center a nearest (výchozí hodnoty jsou pak start). Hodně staré prohlížeče (IE8+) podporují místo objektu pouze boolean, kde TRUE je zarovnání nahoru a FALSE zarovnání dolů (výchozí je TRUE).

el.scrollIntoView({
    behavior: smooth,
    block: start, //nahoru (tedy k první řádce)
    inline: center //na střed v řádce
}
//Jednoduché volání (IE8+)
e.scrollIntoView(true); //zarovnání nahoru

Feature detect

Pro ověření, zda prohlížeč podporuje přichytávání, můžete použít CSS definici @supports() nebo JS funkci CSS.supports(). Pozor ale na to, že vlastnost scroll-snap-type byla nadefinována již v první verzi, kterou podporují starší prohlížeče. Pro ověření nové verze je potřeba použít vlastnost scroll-snap-align:

@supports (scroll-snap-align: start) {
    /* ... definice přichytávání */
}
function scrollIntoView(el) {
    if ('CSS' in window &&
        CSS.supports('scroll-snap-align', 
                            'start')) {
        //scroll pomocí bodů zachycení
        el.scrollIntoView();
    }
    else { //normální scroll na pozici prvku
        window.scrollTo(0, el.offsetTop);
    }
}

//volání vytvořené funkce
window.scrollIntoView(
        document.getElementById('example')
);

 

Napsat komentář

Vaše emailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *