Tworzenie komponentu Karty

Podstawowy przegląd tworzenia komponentu kart podobnego do tych, które występują w aplikacjach na iOS i Androida.

W tym poście chcę podzielić się z Wami swoimi przemyśleniami na temat tworzenia komponentu kart w internecie, który jest elastyczny, obsługuje różne urządzenia wejściowe i działa w różnych przeglądarkach. Wypróbuj wersję demonstracyjną.

Demonstracja

Jeśli wolisz film, oto wersja tego posta w YouTube:

Omówienie

Karty są częstym elementem systemów projektowania, ale mogą przybierać różne kształty i formy. Najpierw były karty na komputery, które były tworzone na podstawie elementu <frame>, a teraz mamy płynne komponenty mobilne, które animują treści na podstawie właściwości fizycznych. Wszystkie mają ten sam cel: oszczędzanie miejsca.

Obecnie podstawą korzystania z kart jest obszar nawigacji z przyciskami, który umożliwia przełączanie widoczności treści w ramce wyświetlania. Wiele różnych obszarów treści zajmuje tę samą przestrzeń, ale są one wyświetlane warunkowo na podstawie przycisku wybranego w nawigacji.

kolaż jest dość chaotyczny ze względu na ogromną różnorodność stylów zastosowanych w koncepcji komponentu
Koloż z uwzględnieniem stylów projektowania stron internetowych komponentów kart z ostatnich 10 lat

Taktyki internetowe

Ogólnie uważam, że tworzenie tego komponentu było dość proste dzięki kilku kluczowym funkcjom platformy internetowej:

  • scroll-snap-points dla płynnych interakcji z użyciem przesuwania i klawiatury z odpowiednimi pozycjami zatrzymania przewijania
  • Precyzyjne linki za pomocą haszy adresów URL w celu obsługi przewijania na stronie i udostępniania przez przeglądarkę
  • Obsługa czytników ekranu za pomocą znaczników elementów <a> i id="#hash"
  • prefers-reduced-motion do włączania przejść i natychmiastowego przewijania na stronie
  • Funkcja @scroll-timeline w wersji roboczej umożliwia dynamiczne podświetlanie i zmienianie koloru wybranej karty

HTML

Podstawowe zasady UX: kliknij link, adres URL reprezentuje zagnieżdżony stan strony, a następnie obserwuj, jak obszar treści zmienia się, gdy przeglądarka przewija do pasującego elementu.

Znajdują się tam elementy strukturalne treści: linki i :target. Potrzebujemy listy linków, do których świetnie nadaje się <nav>, oraz listy elementów <article>, do których świetnie nadaje się <section>. Każdy skrót linku będzie pasować do sekcji, umożliwiając przeglądarce przewijanie za pomocą kotwicy.

Kliknięcie przycisku linku powoduje przesunięcie skoncentrowanego obszaru treści.

Na przykład kliknięcie linku automatycznie spowoduje skupienie się na artykule :target w Chrome 89, bez potrzeby korzystania z JS. Użytkownik może wtedy przewijać treść artykułu za pomocą urządzenia wejściowego w zwykły sposób. Są to treści uzupełniające, jak wskazano w znaczniku.

Do uporządkowania kart użyłem tego znacznika:

<snap-tabs>
  <header>
    <nav>
      <a></a>
      <a></a>
      <a></a>
      <a></a>
    </nav>
  </header>
  <section>
    <article></article>
    <article></article>
    <article></article>
    <article></article>
  </section>
</snap-tabs>

Mogę nawiązywać relacje między elementami <a><article> z usługami hrefid w ten sposób:

<snap-tabs>
  <header>
    <nav>
      <a href="#responsive"></a>
      <a href="#accessible"></a>
      <a href="#overscroll"></a>
      <a href="#more"></a>
    </nav>
  </header>
  <section>
    <article id="responsive"></article>
    <article id="accessible"></article>
    <article id="overscroll"></article>
    <article id="more"></article>
  </section>
</snap-tabs>

Następnie wypełniłam artykuły różnymi ilościami tekstu Lorem Ipsum, a linki różnymi długościami i zestawami tytułów obrazów. Teraz, gdy mamy już materiały, możemy rozpocząć układanie.

układy z przewijaniem,

W tym komponencie występują 3 rodzaje obszarów przewijania:

  • Pasek nawigacyjny (różowy) można przewijać poziomo.
  • Obszar treści (niebieski) można przewijać poziomo.
  • Każdy element artykułu (zielony) można przewijać w pionie.
3 kolorowe pola z kolorami pasującymi do strzałek kierunkowych, które wyznaczają obszary przewijania i pokazują kierunek przewijania.

Istnieją 2 rodzaje elementów związanych z przewijaniem:

  1. Okno
    Pole o określonych wymiarach, które ma styl właściwości overflow.
  2. Powierzchnia o niestandardowych rozmiarach
    W tym układzie są to kontenery listy: linki nawigacyjne, artykuły w sekcji i treści artykułu.

Układ <snap-tabs>

Wybrałem układ najwyższego poziomu flex (Flexbox). Ustawiłem kierunek na column, więc nagłówek i sekcja są uporządkowane pionowo. To pierwsze okno przewijania, które ukrywa wszystko, co jest poza zakresem widoczności. Nagłówek i sekcja będą wkrótce obsługiwać przewijanie, tak jak poszczególne strefy.

HTML
<snap-tabs>
  <header></header>
  <section></section>
</snap-tabs>
CSS
  snap-tabs {
  display: flex;
  flex-direction: column;

  /* establish primary containing box */
  overflow: hidden;
  position: relative;

  & > section {
    /* be pushy about consuming all space */
    block-size: 100%;
  }

  & > header {
    /* defend against 
needing 100% */ flex-shrink: 0; /* fixes cross browser quarks */ min-block-size: fit-content; } }

Wracając do kolorowego diagramu z 3 przewijaniem:

  • <header> jest teraz gotowy do użycia jako (różowy) element przewijania.
  • <section> jest przygotowany do pełnienia roli (niebieskiego) kontenera przewijania.

Ramki wyróżnione poniżej za pomocą VisBug pomagają nam zobaczyć okna utworzone przez przewijane kontenery.

elementy nagłówka i sekcji mają nałożone elementy w kolorze różowym, które wskazują miejsce, jakie zajmują w komponencie.

Układ kart <header>

Kolejny układ jest prawie taki sam: do tworzenia układu pionowego używam elementu flex.

HTML
<snap-tabs>
  <header>
    <nav></nav>
    <span class="snap-indicator"></span>
  </header>
  <section></section>
</snap-tabs>
CSS
header {
  display: flex;
  flex-direction: column;
}

Element .snap-indicator powinien przesuwać się poziomo wraz z grupą linków, a ta opcja układu nagłówka pomaga w tym zadaniu. Nie ma tu elementów z pozycji bezwzględnej.

elementy nawigacji i elementy span.indicator mają nałożone na siebie elementy w różowym kolorze, które wskazują, jaką przestrzeń zajmują w komponencie

Następnie style przewijania. Okazuje się, że możemy udostępniać style przewijania między 2 poziomami przewijania poziomego (nagłówek i sekcja), więc utworzyłem klasę pomocniczą .scroll-snap-x.

.scroll-snap-x {
  /* browser decide if x is ok to scroll and show bars on, y hidden */
  overflow: auto hidden;
  /* prevent scroll chaining on x scroll */
  overscroll-behavior-x: contain;
  /* scrolling should snap children on x */
  scroll-snap-type: x mandatory;

  @media (hover: none) {
    scrollbar-width: none;

    &::-webkit-scrollbar {
      width: 0;
      height: 0;
    }
  }
}

Każdy z nich wymaga przepełnienia na osi x, ograniczeń przewijania, aby zablokować przewijanie, ukrytych suwaków dla urządzeń dotykowych i blokowania obszarów prezentacji treści. Kolejność kart na klawiaturze jest dostępna, a wszelkie interakcje kierują uwagę użytkownika w naturalny sposób. Scrolling snap containery mają też ładne interakcje w stylu karuzeli, które można obsługiwać za pomocą klawiatury.

Układ nagłówka kart <nav>

Linki nawigacyjne muszą być wyrównane w linii, bez dzielenia wierszy, a pośrodku. Każdy element linku powinien być dopasowany do kontenera z dopasowaniem do przewijania. Swift działa w ramach usługi porównywania cen 2021.

HTML
<nav>
  <a></a>
  <a></a>
  <a></a>
  <a></a>
</nav>
CSS
  nav {
  display: flex;

  & a {
    scroll-snap-align: start;

    display: inline-flex;
    align-items: center;
    white-space: nowrap;
  }
}

Każdy link ma swój styl i rozmiar, więc układ nawigacji musi określać tylko kierunek i przepływ. Unikalne szerokości elementów nawigacyjnych sprawiają, że przełączanie się między kartami jest przyjemne, ponieważ wskaźnik dostosowuje swoją szerokość do nowego celu. W zależności od tego, ile elementów znajduje się na stronie, przeglądarka wyświetli suwak lub nie.

elementy nawigacji mają nałożone elementy w różowym kolorze, które wskazują, jaką przestrzeń zajmują w komponencie oraz gdzie się rozszerzają

Układ kart <section>

Ta sekcja jest elementem elastycznym i musi być głównym konsumentem miejsca. Musi też utworzyć kolumny, w których będą umieszczane artykuły. Jeszcze raz dziękujemy za szybkie działanie w sprawie usługi porównywania cen w 2021 r. block-size: 100% rozciąga ten element, aby wypełnił jak najwięcej miejsca w nadrzędnym, a następnie tworzy serię kolumn, które mają 100% szerokość elementu nadrzędnego. Wartości procentowe sprawdzają się tutaj świetnie, ponieważ nałożyliśmy na element nadrzędny silne ograniczenia.

HTML
<section>
  <article></article>
  <article></article>
  <article></article>
  <article></article>
</section>
CSS
  section {
  block-size: 100%;

  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 100%;
}

To tak, jakbyśmy mówili: „Rozszerz się pionowo tak bardzo, jak to możliwe, ale nie przesadzaj” (pamiętaj o nagłówku ustawionym na flex-shrink: 0: jest to zabezpieczenie przed takim rozszerzaniem), co określa wysokość wiersza dla zestawu kolumn o pełnej wysokości. Styl auto-flow informuje siatkę, aby zawsze układała elementy podrzędne w poziomej linii bez przewijania, co jest dokładnie tym, czego potrzebujemy, aby elementy wypełniały okno nadrzędne.

elementy artykułu mają nałożone elementy w kolorze różowym, które wskazują, jaką przestrzeń zajmują w komponencie i gdzie się rozlewają;

Czasami trudno mi to zrozumieć. Ten element sekcji mieści się w pudełku, ale utworzył też zestaw pudełek. Mam nadzieję, że obrazy i wyjaśnienia okażą się przydatne.

Układ kart <article>

Użytkownik powinien mieć możliwość przewijania treści artykułu, a paski przewijania powinny wyświetlać się tylko w przypadku przepełnienia. Te elementy artykułu są ułożone w estetyczny sposób. Są one jednocześnie elementem nadrzędnym i podrzędnym przewijania. Przeglądarka obsługuje tutaj trudne interakcje z użyciem dotyku, myszy i klawiatury.

HTML
<article>
  <h2></h2>
  <p></p>
  <p></p>
  <h2></h2>
  <p></p>
  <p></p>
  ...
</article>
CSS
article {
  scroll-snap-align: start;

  overflow-y: auto;
  overscroll-behavior-y: contain;
}

Wybrałem, aby artykuły były dopasowywane do ich głównego scrollera. Bardzo podoba mi się to, że elementy linków nawigacyjnych i elementy artykułu są dopasowywane do początku swoich kontenerów przewijania. Wygląda to na harmonijny związek.

element artykułu i jego elementy podrzędne mają nałożone na siebie elementy w kolorze różowym, które wskazują miejsce zajmowane przez te elementy w komponencie oraz kierunek, w którym się rozszerzają

Artykuł jest elementem potomnym siatki, a jego rozmiar jest z góry określony jako obszar widoku, w którym chcemy zapewnić użytkownikowi płynne przewijanie. Oznacza to, że nie muszę tutaj określać wysokości ani szerokości, tylko sposób przepełnienia. Ustawiłem overflow-y na auto, a następnie zablokowałem interakcje z przewijaniem za pomocą przydatnej właściwości overscroll-behavior.

Podsumowanie 3 obszarów przewijania

Poniżej w ustawieniach systemu wybrałem opcję „Zawsze pokazuj suwaki”. Uważam, że ważne jest, aby układ działał z włączonym tym ustawieniem, ponieważ chcę sprawdzić układ i zgodność z przewijaniem.

3 paski przewijania są widoczne, zajmują miejsce w układzie, a komponent nadal wygląda świetnie

Widok paska przewijania w tym komponencie pomaga wyraźnie pokazać, gdzie znajdują się obszary przewijania, w jakim kierunku można je przewijać i jak oddziałują na siebie nawzajem. Zastanów się, jak każda z ramek okna przewijania jest elementem nadrzędnym flex lub siatki dla układu.

Narzędzia deweloperskie pomagają nam wizualizować:

obszary przewijania mają nałożone narzędzia siatki i flexboxa, które wskazują, jaką przestrzeń zajmują w komponencie i w którym kierunku się rozlewają
Narzędzie deweloperskie Chromium, które pokazuje układ elementu nawigacji flexboxa wypełnionego elementami kotwicy, układ sekcji siatki wypełnionej elementami artykułu oraz elementy artykułu wypełnione akapitami i elementem nagłówka.

Układy przewijania są kompletne: mają funkcję przyciągania, umożliwiają tworzenie precyzyjnych linków i są dostępne za pomocą klawiatury. Solidne podstawy, które umożliwiają ulepszanie interfejsu, styl i przyjemność.

Wyróżniona funkcja

Podczas przewijania przytrzymane elementy zachowują swoją pozycję. Oznacza to, że JavaScript nie musi wyświetlać niczego po obróceniu urządzenia ani zmianie rozmiaru przeglądarki. Wypróbuj to w Chromium DevTools w trybie urządzenia, wybierając dowolny tryb inny niż Responsive, a następnie zmień rozmiar ramki urządzenia. Zwróć uwagę, że element pozostaje widoczny i zablokowany wraz z treścią. Jest ona dostępna od czasu, gdy Chromium zaktualizowało implementację, aby była zgodna ze specyfikacją. Więcej informacji znajdziesz w tym poście na blogu.

Animacja

Celem animacji jest wyraźne powiązanie interakcji z informacjami zwrotnymi interfejsu. Pomaga to użytkownikowi w łatwym znalezieniu wszystkich treści. Dodaję animację w celowy sposób i bezwarunkowo. Użytkownicy mogą teraz określić swoje preferencje dotyczące ruchu w systemie operacyjnym, a ja bardzo chętnie dostosowuję moje interfejsy do ich preferencji.

Połączę podkreślenie karty z pozycją przewijania artykułu. Dopasowywanie to nie tylko ładne wyrównanie, ale też zakotwiczenie początku i końca animacji. Dzięki temu <nav>, który działa jak minimapa, pozostaje połączony z treścią. Sprawdzamy preferencje użytkownika dotyczące animacji zarówno w CSS, jak i JS. Oto kilka świetnych miejsc, w których warto być uprzejmy.

Zachowanie podczas przewijania

Można ulepszyć zachowanie ruchu w przypadku :targetelement.scrollIntoView(). Domyślnie jest to natychmiastowe. Przeglądarka ustawia tylko pozycję przewijania. Co zrobić, jeśli chcemy przejść do pozycji przewijania zamiast migać?

@media (prefers-reduced-motion: no-preference) {
  .scroll-snap-x {
    scroll-behavior: smooth;
  }
}

Wprowadzamy tu ruch, nad którym użytkownik nie ma kontroli (np. przewijanie), dlatego stosujemy ten styl tylko wtedy, gdy użytkownik nie ma ustawień dotyczących ograniczenia ruchu w systemie operacyjnym. W ten sposób wprowadzamy tę funkcję tylko dla osób, które się na to zgadzają.

Wskaźnik kart

Celem tej animacji jest pomoc w powiązaniu wskaźnika ze stanem treści. Postanowiłam użyć stylu border-bottom dla użytkowników, którzy wolą ograniczony ruch, oraz animacji przesuwania połączonej z kolorowym przejściem dla użytkowników, którym nie przeszkadza ruch.

W Chromium Devtools mogę przełączyć ustawienie i zademonstrować 2 różne style przejścia. Miałem dużo zabawy podczas tworzenia tego projektu.

@media (prefers-reduced-motion: reduce) {
  snap-tabs > header a {
    border-block-end: var(--indicator-size) solid hsl(var(--accent) / 0%);
    transition: color .7s ease, border-color .5s ease;

    &:is(:target,:active,[active]) {
      color: var(--text-active-color);
      border-block-end-color: hsl(var(--accent));
    }
  }

  snap-tabs .snap-indicator {
    visibility: hidden;
  }
}

Ukrywam .snap-indicator, gdy użytkownik woli ograniczone ruchy, ponieważ nie jest już potrzebne. Następnie zastępuję je stylami border-block-end i elementem transition. Zwróć też uwagę, że podczas interakcji z kartami aktywny element nawigacji ma nie tylko podkreślenie marki, ale też ciemniejszy kolor tekstu. Aktywny element ma większy kontrast kolorów tekstu i jasny akcent podświetlenia.

Wystarczy kilka dodatkowych linii kodu CSS, aby użytkownik poczuł, że jest widziany (w tym sensie, że świadomie respektujemy jego preferencje dotyczące animacji). Uwielbiam to.

@scroll-timeline

W poprzedniej sekcji pokazałem, jak obsługiwać płynne przejścia między stylami w przypadku ograniczonego ruchu. W tej sekcji pokażę, jak połączyć ze sobą wskaźnik i obszar przewijania. Teraz kilka eksperymentalnych ciekawostek. Mam nadzieję, że nie możesz się już doczekać.

const { matches:motionOK } = window.matchMedia(
  '(prefers-reduced-motion: no-preference)'
);

Najpierw sprawdzam preferencje użytkownika dotyczące ruchu w JavaScript. Jeśli wynik tego testu to false, co oznacza, że użytkownik preferuje ograniczone ruchy, nie uruchamiamy żadnych efektów ruchu łączenia podczas przewijania.

if (motionOK) {
  // motion based animation code
}

W momencie pisania tego tekstu obsługa przeglądarki dla @scroll-timeline nie jest dostępna. Jest to projekt specyfikacji zawierający tylko eksperymentalne implementacje. Ma jednak polyfill, którego używam w tym demo.

ScrollTimeline

Zarówno CSS, jak i JavaScript mogą tworzyć osi czasu przewijania, ale wybrałem JavaScript, aby móc używać w animacji pomiarów elementów na żywo.

const sectionScrollTimeline = new ScrollTimeline({
  scrollSource: tabsection,  // snap-tabs > section
  orientation: 'inline',     // scroll in the direction letters flow
  fill: 'both',              // bi-directional linking
});

Chcę, aby 1 element podążał za pozycją przewijania innego elementu. Tworząc ScrollTimeline, definiuję element sterujący linkiem przewijania, czyli scrollSource. Zazwyczaj animacja w internecie działa zgodnie z globalnym interwałem czasowym, ale dzięki niestandardowemu sectionScrollTimeline w pamięci mogę to zmienić.

tabindicator.animate({
    transform: ...,
    width: ...,
  }, {
    duration: 1000,
    fill: 'both',
    timeline: sectionScrollTimeline,
  }
);

Zanim przejdę do klatek kluczowych animacji, chcę zwrócić uwagę, że element tabindicator będzie animowany na podstawie niestandardowej osi czasu, czyli przewijania sekcji. W ten sposób tworzysz połączenie, ale brakuje ostatniego składnika, czyli punktów stanu, które będą animowane, czyli keyframe’ów.

Klatki kluczowe dynamiczne

Istnieje bardzo skuteczny, czysto deklaratywny sposób tworzenia animacji za pomocą @scroll-timeline, ale wybrana przeze mnie animacja była zbyt dynamiczna. Nie ma możliwości przejścia między auto szerokością, a także dynamicznego tworzenia liczby klatek kluczowych na podstawie długości elementów potomnych.

JavaScript wie, jak uzyskać te informacje, więc sami przejdziemy przez elementy potomne i pobierać obliczone wartości w czasie wykonywania:

tabindicator.animate({
    transform: [...tabnavitems].map(({offsetLeft}) =>
      `translateX(${offsetLeft}px)`),
    width: [...tabnavitems].map(({offsetWidth}) =>
      `${offsetWidth}px`)
  }, {
    duration: 1000,
    fill: 'both',
    timeline: sectionScrollTimeline,
  }
);

W przypadku każdego elementu tabnavitem zdestrukturuj pozycję offsetLeft i zwróć ciąg znaków, który używa jej jako wartości translateX. Spowoduje to utworzenie 4 keyframe’ów transformacji dla animacji. To samo dotyczy szerokości. Każdy obrazek pytany jest o swoją dynamiczną szerokość, która jest potem używana jako wartość kluczowego obrazu.

Oto przykładowe dane wyjściowe na podstawie moich preferencji dotyczących czcionek i przeglądarki:

Klatki kluczowe TranslateX:

[...tabnavitems].map(({offsetLeft}) =>
  `translateX(${offsetLeft}px)`)

// results in 4 array items, which represent 4 keyframe states
// ["translateX(0px)", "translateX(121px)", "translateX(238px)", "translateX(464px)"]

Klatki kluczowe szerokości:

[...tabnavitems].map(({offsetWidth}) =>
  `${offsetWidth}px`)

// results in 4 array items, which represent 4 keyframe states
// ["121px", "117px", "226px", "67px"]

Aby podsumować strategię, wskaźnik karty będzie się teraz animować w 4 klatkach kluczowych w zależności od pozycji przyciągania sekcji w rolce. Punkty zaczepienia tworzą wyraźne rozgraniczenie między klatkami kluczowymi i znacznie zwiększają wrażenie synchronizacji animacji.

aktywna i nieaktywna karta są wyświetlane z nakładkami VisBug, które pokazują akceptowalne wyniki kontrastu dla obu kart

Użytkownik uruchamia animację za pomocą interakcji, a szerokość i położenie wskaźnika zmieniają się z sekcji na sekcję, idealnie dopasowując się do przewijania.

Może nie zauważysz, ale jestem bardzo dumny z przejścia koloru w momencie wybrania wyróżnionego elementu nawigacji.

Jasniejszy szary kolor niewybranego elementu jest jeszcze bardziej oddalony, gdy wyróżniony element ma większy kontrast. Zmiana koloru tekstu jest powszechna, np. podczas najechania kursorem i po wybraniu, ale przejście koloru podczas przewijania, zsynchronizowane z wskaźnikiem podkreślenia, to już poziom zaawansowania.

Oto jak to zrobiłem:

tabnavitems.forEach(navitem => {
  navitem.animate({
      color: [...tabnavitems].map(item =>
        item === navitem
          ? `var(--text-active-color)`
          : `var(--text-color)`)
    }, {
      duration: 1000,
      fill: 'both',
      timeline: sectionScrollTimeline,
    }
  );
});

Każdy link nawigacyjny na karcie musi mieć tę nową animację kolorów, która śledzi tę samą oś czasu przewijania co podkreślenie. Używam tej samej osi czasu co wcześniej: ponieważ jej zadaniem jest emitowanie znacznika wyboru podczas przewijania, możemy go używać w dowolnym typie animacji. Tak jak wcześniej, w pętli utworzyłem 4 kluczowe klatki i zwracam kolory.

[...tabnavitems].map(item =>
  item === navitem
    ? `var(--text-active-color)`
    : `var(--text-color)`)

// results in 4 array items, which represent 4 keyframe states
// [
  "var(--text-active-color)",
  "var(--text-color)",
  "var(--text-color)",
  "var(--text-color)",
]

Keyframe z kolorem var(--text-active-color) wyróżnia link, a poza tym ma standardowy kolor tekstu. Zagnieżdżona pętla sprawia, że jest to stosunkowo proste, ponieważ pętla zewnętrzna to każdy element nawigacji, a pętla wewnętrzna to osobne klatki kluczowe każdego z tych elementów. Sprawdzam, czy element zewnętrznego pętli jest taki sam jak element wewnętrznego pętli, i na tej podstawie określam, kiedy jest wybrany.

Miałem dużo zabawy, pisząc ten artykuł. Ogromnie.

Jeszcze więcej ulepszeń JavaScriptu

Warto przypomnieć, że główna część tego, co tu pokazuję, działa bez JavaScriptu. Zobaczmy, jak możemy to ulepszyć, gdy JavaScript jest dostępny.

Precyzyjne linki to termin bardziej związany z urządzeniami mobilnymi, ale myślę, że intencje związane z precyzyjnymi linkami są spełnione dzięki temu, że możesz udostępniać adres URL bezpośrednio w ramach karty. Przeglądarka przejdzie na stronie do identyfikatora dopasowanego w haszu adresu URL. Okazało się, że ten onload handler działa na różnych platformach.

window.onload = () => {
  if (location.hash) {
    tabsection.scrollLeft = document
      .querySelector(location.hash)
      .offsetLeft;
  }
}

Synchronizacja końca przewijania

Nasi użytkownicy nie zawsze klikają lub używają klawiatury. Czasami po prostu przewijają bez przeszkód, jak powinni. Gdy przewijanie sekcji się zatrzyma, miejsce, w którym się zatrzyma, musi pasować do paska nawigacji u góry.

Oto jak czekam na koniec przewijania: js tabsection.addEventListener('scroll', () => { clearTimeout(tabsection.scrollEndTimer); tabsection.scrollEndTimer = setTimeout(determineActiveTabSection, 100); });

Gdy przewijasz sekcje, wyczyść limit czasu sekcji (jeśli jest) i rozpocznij nową. Gdy przestaniesz przewijać sekcje, nie anuluj limitu czasu i uruchom po 100 ms. Gdy zostanie wywołany, wywołuje funkcję, która określa, gdzie użytkownik zatrzymał się w odtwarzaniu.

const determineActiveTabSection = () => {
  const i = tabsection.scrollLeft / tabsection.clientWidth;
  const matchingNavItem = tabnavitems[i];

  matchingNavItem && setActiveTab(matchingNavItem);
};

Zakładając, że przewijanie jest zablokowane, podzielenie bieżącej pozycji przewijania przez szerokość obszaru przewijania powinno dać liczbę całkowitą, a nie ułamek dziesiętny. Następnie próbuję pobrać element nawigacyjny z naszej pamięci podręcznej za pomocą tego wyliczonego indeksu. Jeśli coś znajdzie, wysyłam dopasowanie, aby ustawić je jako aktywne.

const setActiveTab = tabbtn => {
  tabnav
    .querySelector(':scope a[active]')
    .removeAttribute('active');

  tabbtn.setAttribute('active', '');
  tabbtn.scrollIntoView();
};

Ustawienie aktywnej karty rozpoczyna się od wyczyszczenia wszystkich obecnie aktywnych kart, a następnie nadania atrybutu aktywnego stanu elementowi nawigacji przychodzącej. Wywołanie funkcji scrollIntoView() ma ciekawą interakcję z usługą porównywania cen, na którą warto zwrócić uwagę.

.scroll-snap-x {
  overflow: auto hidden;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;

  @media (prefers-reduced-motion: no-preference) {
    scroll-behavior: smooth;
  }
}

W CSS narzędzia do korzystania z przewijania poziomego zagnieżdżyliśmy zapytanie o media, które stosuje przewijanie smooth, jeśli użytkownik toleruje ruch. Kod JavaScript może swobodnie wywoływać metody, aby przewijać elementy do widoku, a kod CSS może deklaratywnie zarządzać UX. Czasami tworzą naprawdę urocze pary.

Podsumowanie

Teraz, gdy już wiesz, jak to zrobić, jak Ty to zrobisz? To tworzy ciekawą architekturę komponentów. Kto przygotuje pierwszą wersję z miejscami na reklamy w ulubionej platformie? 🙂

Zróżnicujemy nasze podejścia i poznamy wszystkie sposoby tworzenia stron internetowych. Utwórz Glitch, wyślij mi tweeta ze swoją wersją, a ja dodam ją do sekcji Remiksy społeczności poniżej.

Remiksy społeczności