Tworzenie komponentu przewijanego obrazu

Podstawowe informacje o tym, jak utworzyć elastyczny widok przewijania w poziomie na telewizory, telefony, komputery itp.

W tym poście chcę podzielić się przemyśleniami na temat tworzenia w internecie minimalistycznych, responsywnych i dostępnych doświadczeń z przewijaniem w poziomie, które działają w różnych przeglądarkach i na różnych platformach (np. telewizorach). Wypróbuj wersję demonstracyjną.

Wersja demonstracyjna

Jeśli wolisz film, obejrzyj tę wersję posta w YouTube:

Przegląd

Przygotujemy układ z przewijaniem w poziomie, który będzie służyć do hostowania miniatur multimediów lub produktów. Komponent zaczyna się jako zwykła <ul> lista, ale za pomocą CSS przekształca się w satysfakcjonujące i płynne przewijanie, które wyświetla obrazy i przyciąga je do siatki. Dodaliśmy JavaScript, aby ułatwić interakcje z indeksem ruchomym, dzięki czemu użytkownicy klawiatury mogą pominąć przechodzenie przez ponad 100 elementów. Dodatkowo używamy eksperymentalnego zapytania o media prefers-reduced-data, aby przekształcić przewijanie multimediów w lekkie przewijanie tytułów.

Zacznij od dostępnego kodu

Przewijanie multimediów składa się tylko z kilku podstawowych komponentów, czyli listy z elementami. Lista w najprostszej formie może być używana na całym świecie i zrozumiała dla wszystkich. Użytkownik, który trafi na tę stronę, może przeglądać listę i kliknąć link, aby wyświetlić produkt. To nasza baza z ułatwieniami dostępu.

Dostarcz listę z elementem <ul>:

<ul class="horizontal-media-scroller">
  <li></li>
  <li></li>
  <li></li>
  ...
<ul>

Spraw, aby elementy listy były interaktywne za pomocą elementu <a>:

<li>
  <a href="#">
    ...
  </a>
</li>

Użyj elementu <figure>, aby semantycznie przedstawić obraz i jego podpis:

<figure>
  <picture>
    <img alt="..." loading="lazy" src="https://picsum.photos/500/500?1">
  </picture>
  <figcaption>Legends</figcaption>
</figure>

Zwróć uwagę na atrybuty altloading w elemencie <img>. Tekst alternatywny do przewijania multimediów to możliwość poprawy UX, która pozwala dodać do miniatury dodatkowy kontekst lub użyć tekstu zastępczego, jeśli obraz się nie wczytał. Umożliwia też użytkownikom korzystającym z technologii wspomagających, takich jak czytniki ekranu, korzystanie z interfejsu głosowego. Więcej informacji znajdziesz w artykule 5 złotych zasad dotyczących zgodnego tekstu alternatywnego.

Atrybut loading akceptuje słowo kluczowe lazy, które sygnalizuje, że źródło obrazu powinno być pobierane tylko wtedy, gdy obraz znajduje się w obszarze widocznym. Może to być bardzo przydatne w przypadku długich list, ponieważ użytkownicy będą pobierać tylko obrazy elementów, które przewinęli.

Obsługa preferowanego schematu kolorów użytkownika

Użyj tagu color-scheme jako tagu <meta>, aby poinformować przeglądarkę, że strona chce korzystać ze stylów agenta użytkownika w wersji jasnej i ciemnej. Jest to bezpłatny tryb ciemny lub jasny, w zależności od tego, jak na to spojrzysz:

<meta name="color-scheme" content="dark light">

Tag meta dostarcza najwcześniejszy możliwy sygnał, dzięki czemu przeglądarka może wybrać ciemny domyślny kolor obszaru roboczego, jeśli użytkownik preferuje ciemny motyw. Oznacza to, że podczas przechodzenia między stronami witryny nie będzie migać białe tło. Płynne przełączanie się między ciemnym motywem podczas ładowania, co jest znacznie przyjemniejsze dla oczu.

Więcej informacji znajdziesz w artykule Thomasa Steinera na stronie https://web.dev/color-scheme/.

Dodaj treść

Biorąc pod uwagę powyższą strukturę treści ul > li > a > figure > picture > img, kolejnym zadaniem jest dodanie obrazów i tytułów, które można przewijać. W wersji demonstracyjnej umieściłem statyczne obrazy i tekst zastępczy, ale możesz użyć swojego ulubionego źródła danych.

Dodawanie stylu za pomocą CSS

Teraz usługa porównywania cen może wziąć tę ogólną listę treści i przekształcić ją w atrakcyjną formę. Netflix, sklepy z aplikacjami i wiele innych witryn oraz aplikacji używa obszarów przewijanych w poziomie, aby wypełnić obszar widoczny kategoriami i opcjami.

Tworzenie układu przewijania

Ważne jest, aby unikać obcinania treści w układach lub polegania na obcinaniu tekstu za pomocą wielokropka. Wiele telewizorów ma przewijarki multimediów, takie jak ta, ale zbyt często uciekają się do pomijania treści. Ten układ nie! Umożliwia też zastąpienie rozmiaru kolumny przez treść multimedialną, dzięki czemu 1 układ jest wystarczająco elastyczny, aby obsługiwać wiele ciekawych kombinacji.

2 wyświetlane wiersze przewijania. Pierwszy nie ma wielokropka, co oznacza, że jest wyższy i każdy tytuł jest w pełni czytelny. Druga jest krótsza, a wiele tytułów jest uciętych z wielokropkiem.

Kontener umożliwia zastąpienie rozmiaru kolumny przez podanie domyślnego rozmiaru jako właściwości niestandardowej. Ten układ siatki ma określony rozmiar kolumn, a zarządza tylko odstępami i kierunkiem:

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2); /* parent owned value for children to be relative to*/
  margin: 0;
}

Właściwość niestandardowa jest następnie używana przez element <picture> do utworzenia podstawowego współczynnika proporcji: pola:

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  & picture {
    inline-size: var(--size);
    block-size: var(--size);
  }
}

Dodaj jeszcze tylko kilka drobnych stylów, aby dokończyć podstawową wersję przewijania multimediów:

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  overflow-x: auto;
  overscroll-behavior-inline: contain;

  & > li {
    display: inline-block; /* removes the list-item bullet */
  }

  & picture {
    inline-size: var(--size);
    block-size: var(--size);
  }
}

Ustawienie overflow umożliwia przewijanie i nawigację za pomocą klawiatury po liście elementów <ul>, a następnie usuwa atrybut ::marker z każdego bezpośredniego elementu podrzędnego <li>, przypisując mu nowy typ wyświetlania inline-block.

Obrazy nie są jeszcze elastyczne i wychodzą poza ramki, w których się znajdują. Dopasuj je do swoich potrzeb, wybierając rozmiar, krój i styl obramowania, a także gradient tła, który będzie widoczny podczas leniwego ładowania:

img {
  /* smash into whatever box it's in */
  inline-size: 100%;
  block-size: 100%;

  /* don't squish but do cover the space */
  object-fit: cover;

  /* soften the edges */
  border-radius: 1ex;
  overflow: hidden;

  /* if empty, show a gradient placeholder */
  background-image:
    linear-gradient(
      to bottom,
      hsl(0 0% 40%),
      hsl(0 0% 20%)
    );
}

Dopełnienie przewijania

Dopasowanie do treści strony oraz powierzchnia przewijania od krawędzi do krawędzi mają kluczowe znaczenie dla harmonijnego i minimalistycznego komponentu.

Aby uzyskać układ przewijania od krawędzi do krawędzi, który jest zgodny z naszą typografią i liniami układu, użyj padding, które pasuje do scroll-padding:

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  overflow-x: auto;
  overscroll-behavior-inline: contain;

  padding-inline: var(--gap);
  scroll-padding-inline: var(--gap);
  padding-block: calc(var(--gap) / 2); /* make space for scrollbar and focus outline */
}

Poprawka błędu dopełnienia przewijania w poziomie Powyższy przykład pokazuje, jak łatwo można dodać do kontenera przewijania dopełnienie, ale nadal występują problemy ze zgodnością (rozwiązane w Chromium 91 i nowszych wersjach). Więcej informacji o historii znajdziesz tutaj, ale w skrócie: w widoku przewijania nie zawsze uwzględniano dopełnienie.

Po stronie końca wiersza ostatniego elementu listy jest wyróżnione pole, które pokazuje, że do uzyskania pożądanego wyrównania dopełnienie i element mają tę samą szerokość.

Aby oszukać przeglądarki i sprawić, że dopełnienie pojawi się na końcu przewijanej listy, wybiorę ostatnią liczbę na każdej liście i dodam element pozorny, który będzie miał rozmiar dopełnienia.

.horizontal-media-scroller > li:last-of-type figure {
  position: relative;

  &::after {
    content: "";
    position: absolute;

    inline-size: var(--gap);
    block-size: 100%;

    inset-block-start: 0;
    inset-inline-end: calc(var(--gap) * -1);
  }
}

Używanie właściwości logicznych umożliwia działanie przewijania multimediów w dowolnym trybie pisania i kierunku dokumentu.

Przewijanie z przyciąganiem

Kontener z przewijaniem i przepełnieniem może stać się przyciągającym obszarem widoku za pomocą jednego wiersza kodu CSS. Następnie elementy podrzędne określają, jak mają się wyrównywać do tego obszaru widoku.

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  overflow-x: auto;
  overscroll-behavior-inline: contain;

  padding-inline: var(--gap);
  scroll-padding-inline: var(--gap);
  padding-block-end: calc(var(--gap) / 2);

  scroll-snap-type: inline mandatory;

  & figure {
    scroll-snap-align: start;
  }
}

Koncentracja

Inspiracją dla tego komponentu jest jego ogromna popularność na telewizorach, w sklepach z aplikacjami i innych miejscach. Wiele platform do gier wideo używa przewijania multimediów bardzo podobnego do tego jako głównego układu ekranu głównego. Skupienie jest tu bardzo ważne, a nie tylko niewielkim dodatkiem. Wyobraź sobie, że używasz tego przewijania multimediów na kanapie za pomocą pilota. Możesz wprowadzić niewielkie ulepszenia tej interakcji:

.horizontal-media-scroller a {
  outline-offset: 12px;

  &:focus {
    outline-offset: 7px;
  }

  @media (prefers-reduced-motion: no-preference) {
    & {
      transition: outline-offset .25s ease;
    }
  }
}

Spowoduje to odsunięcie stylu konturu zaznaczenia 7px od pola, co zapewni mu odpowiednią przestrzeń. Jeśli użytkownik nie ma preferencji dotyczących ograniczenia ruchu, przesunięcie jest zmieniane, co powoduje subtelny ruch w przypadku zdarzenia związanego z fokusem.

Indeks ruchomy

Użytkownicy gamepadów i klawiatur wymagają szczególnej uwagi w przypadku długich list przewijanych treści i opcji. Typowym wzorcem rozwiązywania tego problemu jest ruchomy indeks. Dzieje się tak, gdy kontener elementów jest zaznaczony za pomocą klawiatury, ale tylko 1 element podrzędny może być zaznaczony w danym momencie. Ten sposób działania, w którym w danym momencie można wybrać tylko 1 element, ma na celu umożliwienie pominięcia potencjalnie długiej listy elementów, zamiast naciskania klawisza Tab ponad 50 razy, aby dotrzeć do końca.

W pierwszym przewijanym elemencie wersji demonstracyjnej znajduje się 300 pozycji. Możemy zrobić więcej niż tylko zmuszać użytkowników do przechodzenia przez wszystkie te elementy, aby dotrzeć do następnej sekcji.

Aby to zrobić, JavaScript musi obserwować zdarzenia klawiatury i zdarzenia związane z ogniskiem. Aby ułatwić osiągnięcie tego celu, stworzyłem małą bibliotekę open source w npm. Oto jak używać tego narzędzia w przypadku 3 przewijanych sekcji:

import {rovingIndex} from 'roving-ux';

rovingIndex({
  element: someElement
});

W tym przykładzie wysyłamy zapytanie do dokumentu o elementy przewijane i dla każdego z nich wywołujemy funkcję rovingIndex(). Przekaż element rovingIndex(), aby uzyskać efekt wędrownego zaznaczenia, np. kontener listy, oraz selektor zapytania docelowego, jeśli elementy docelowe zaznaczenia nie są bezpośrednimi elementami podrzędnymi.

document.querySelectorAll('.horizontal-media-scroller')
  .forEach(scroller =>
    rovingIndex({
      element: scroller,
      target: 'a',
}))

Więcej informacji o tym efekcie znajdziesz w bibliotece open source roving-ux.

Format obrazu

W momencie pisania tego posta obsługaaspect-ratio jest dostępna w Firefoxie za pomocą flagi, ale w przeglądarkach opartych na Chromium i dekoderach jest dostępna od razu. Układ siatki przewijania multimediów określa tylko kierunek i odstępy, więc rozmiar może się zmieniać w zapytaniu o media, które sprawdza obsługę współczynnika proporcji. Stopniowe ulepszanie niektórych bardziej dynamicznych przewijanych multimediów.

Obok innych używanych proporcji obrazu, czyli 16:9 i 4:3, wyświetla się pole o proporcjach 4:4.

@supports (aspect-ratio: 1) {
  .horizontal-media-scroller figure > picture {
    inline-size: auto; /* for a block-size driven ratio */
    aspect-ratio: 1; /* boxes by default */

    @nest section:nth-child(2) & {
      aspect-ratio: 16/9;
    }

    @nest section:nth-child(3) & {
      /* double the size of the others */
      block-size: calc(var(--size) * 2);
      aspect-ratio: 4/3;

      /* adjust size to fit more items into the viewport */
      @media (width <= 480px) {
        block-size: calc(var(--size) * 1.5);
      }
    }
  }
}

Jeśli przeglądarka obsługuje składnię aspect-ratio, rozmiar obrazów w przewijarce multimediów zostanie zwiększony do aspect-ratio. Korzystając z syntaktyki zagnieżdżania wersji roboczych, możesz zmieniać współczynnik proporcji każdego obrazu w zależności od tego, czy znajduje się on w pierwszym, drugim czy trzecim wierszu. Składnia zagnieżdżania umożliwia też wprowadzanie niewielkich korekt widocznego obszaru bezpośrednio w logice określania rozmiaru.

Dzięki temu kodowi CSS, gdy funkcja będzie dostępna w większej liczbie silników przeglądarek, będzie można łatwo zarządzać bardziej atrakcyjnym wizualnie układem.

Preferuje mniejszą ilość danych

Ta technika jest dostępna tylko za flagąCanary, ale chcę pokazać, jak za pomocą kilku wierszy kodu CSS można znacznie skrócić czas wczytywania strony i zmniejszyć zużycie danych. prefers-reduced-dataZapytanie o media z poziomu 5 umożliwia sprawdzenie, czy urządzenie jest w dowolnym stanie ograniczonego przesyłania danych, np. w trybie oszczędzania danych. Jeśli tak jest, mogę zmodyfikować dokument, a w tym przypadku ukryć obrazy.

ALT_TEXT_HERE

figure {
  @media (prefers-reduced-data: reduce) {
    & {
      min-inline-size: var(--size);

      & > picture {
        display: none;
      }
    }
  }
}

Treści są nadal dostępne, ale bez konieczności pobierania dużych obrazów. Oto witryna przed dodaniem prefers-reduced-data kodu CSS:

(7 żądań, 100 KB zasobów w 131 ms)

ALT_TEXT_HERE

Oto wydajność witryny po dodaniu prefers-reduced-data CSS:

ALT_TEXT_HERE

(71 żądań, 1,2 MB zasobów w 1,07 s)

64 mniej żądań, czyli około 60 obrazów w obszarze widocznym na karcie przeglądarki (testy przeprowadzono na ekranie szerokoekranowym), przyspieszenie wczytywania strony o około 80% i 10% danych przesyłanych przez sieć. Dość zaawansowany CSS.

Podsumowanie

Teraz, gdy wiesz, jak to zrobiłem, jak Ty byś to zrobił? 🙂

Urozmaićmy nasze podejście i poznajmy wszystkie sposoby tworzenia treści w internecie. Utwórz Codepen lub hostuj własną wersję demonstracyjną, wyślij mi ją w tweecie, a ja dodam ją do sekcji Remixy społeczności poniżej.

Źródło

Remiksy społeczności

Na razie jest tu pusto