Tworzenie komponentu bocznego

Podstawowy przegląd tworzenia elastycznego paska bocznego z przesuwnym menu

W tym poście chcę podzielić się z Wami tym, jak stworzyłem prototyp komponentu Sidenav na potrzeby internetu, który jest elastyczny, stanowy, obsługuje nawigację za pomocą klawiatury, działa z JavaScriptem i bez niego oraz działa we wszystkich przeglądarkach. Wypróbuj wersję demonstracyjną.

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

Omówienie

Budowanie elastycznego systemu nawigacji jest trudne. Niektórzy użytkownicy będą korzystać z klawiatury, inni będą mieć wydajne komputery stacjonarne, a jeszcze inni będą wchodzić na stronę z małego urządzenia mobilnego. Każdy użytkownik powinien mieć możliwość otwierania i zamykania menu.

Demonstracja przejścia z wersji na komputer na wersję responsywną na urządzenia mobilne
Tematyka jasna i ciemna na iOS i Androidzie

Taktyki internetowe

W tej eksploracji komponentów połączyłem kilka kluczowych funkcji platformy internetowej:

  1. CSS :target
  2. siatka w CSS,
  3. przekształcenia w CSS,
  4. Zapytania multimedialne CSS dotyczące widocznego obszaru i preferencji użytkownika
  5. JS do focus ulepszeń UX

Moje rozwiązanie ma 1 pasek boczny i przełączniki tylko w przypadku obszaru „mobilnego” o wymiarach 540px lub mniejszych. Punkt graniczny 540px będzie punktem przełączania się między interaktywnym układem mobilnym a statycznym układem na komputery.

Pseudoklasa CSS :target

Jeden link <a> ustawia skrót adresu URL na #sidenav-open, a drugi na pusty (''). Na koniec element ma wartość id, która pasuje do skrótu:

<a href="#sidenav-open" id="sidenav-button" title="Open Menu" aria-label="Open Menu">

<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu"></a>

<aside id="sidenav-open">
  …
</aside>

Kliknięcie każdego z tych linków zmienia stan szyfrowania adresu URL strony, a potem za pomocą pseudoklasy wyświetlam i ukrywanie menu bocznego:

@media (max-width: 540px) {
  #sidenav-open {
    visibility: hidden;
  }

  #sidenav-open:target {
    visibility: visible;
  }
}

Siatka CSS

Wcześniej używałem tylko układów i komponentów z pozycją bezwzględną lub stałą. Jednak dzięki użyciu składni grid-area możemy przypisać wiele elementów do tego samego wiersza lub tej samej kolumny.

Stosy

Główny element układu #sidenav-container to siatka, która tworzy 1 wiersz i 2 kolumny, z których każda ma nazwę stack. Gdy przestrzeń jest ograniczona, CSS przypisuje wszystkie elementy podrzędne elementu <main> do tej samej nazwy siatki, umieszczając wszystkie elementy w tym samym miejscu, tworząc stos.

#sidenav-container {
  display: grid;
  grid: [stack] 1fr / min-content [stack] 1fr;
  min-height: 100vh;
}

@media (max-width: 540px) {
  #sidenav-container > * {
    grid-area: stack;
  }
}

<aside> to animowany element zawierający pasek nawigacji bocznej. Zawiera 2 elementy podrzędne: kontener nawigacyjny <nav> o nazwie [nav] i tło <a> o nazwie [escape], które służy do zamykania menu.

#sidenav-open {
  display: grid;
  grid-template-columns: [nav] 2fr [escape] 1fr;
}

Dostosuj wartości 2fr1fr, aby znaleźć odpowiedni stosunek dla menu nakładki i przycisku zamknięcia w pustej przestrzeni.

Demo, co się dzieje, gdy zmieniasz współczynnik.

Przekształcenia i przejścia CSS 3D

Układ jest teraz ułożony w wielkości widocznego obszaru na urządzeniu mobilnym. Dopóki nie dodam nowych stylów, będzie on domyślnie nakładał się na tekst. Oto kilka przykładów UX, do których dążę w następnej sekcji:

  • Animowanie otwierania i zamykania
  • animacja może być używana tylko wtedy, gdy użytkownik wyrazi na to zgodę;
  • Animuj visibility, aby zaznaczenie klawiatury nie przenosiło się na element poza ekranem

Gdy zaczynam wdrażać animacje ruchu, chcę zacząć od dostępności.

Dostępność ruchu

Nie wszyscy użytkownicy będą chcieli korzystać z funkcji przesuwania. W naszym rozwiązaniu ta preferencja jest stosowana przez dostosowanie zmiennej --duration w arkuszu CSS w zapytaniu o multimedia. Ta wartość zapytania o multimedia reprezentuje preferencje użytkownika dotyczące animacji (jeśli są dostępne) w systemie operacyjnym.

#sidenav-open {
  --duration: .6s;
}

@media (prefers-reduced-motion: reduce) {
  #sidenav-open {
    --duration: 1ms;
  }
}
Demonstracja interakcji z czasem trwania i bez niego.

Gdy użytkownik przesuwa panel boczny, aby go otworzyć lub zamknąć, a on woli ograniczone animacje, element jest natychmiast wyświetlany, zachowując stan bez animacji.

Przejście, przekształcenie, tłumaczenie

Sidenav out (domyślnie)

Aby ustawić domyślny stan paska bocznego na urządzeniu mobilnym jako stan poza ekranem, umieść element za pomocą transform: translateX(-110vw).

Do typowego kodu offscreen -100vw dodałem jeszcze 10vw, aby box-shadow paska boczna nie była widoczna w głównym widoku, gdy jest ukryta.

@media (max-width: 540px) {
  #sidenav-open {
    visibility: hidden;
    transform: translateX(-110vw);
    will-change: transform;
    transition:
      transform var(--duration) var(--easeOutExpo),
      visibility 0s linear var(--duration);
  }
}
Pasek boczny

Gdy element #sidenav pasuje do wartości :target, ustaw pozycję translateX() na pozycję wyjściową 0. Gdy zmienisz hasz URL, element przesunie się z pozycji wyjściowej -110vw na pozycję „wewnątrz” 0 nad pozycją var(--duration).

@media (max-width: 540px) {
  #sidenav-open:target {
    visibility: visible;
    transform: translateX(0);
    transition:
      transform var(--duration) var(--easeOutExpo);
  }
}

Widoczność przejścia

Naszym celem jest teraz ukrycie menu przed czytnikami ekranu, gdy jest ono wyświetlane, aby systemy nie przenosiły punktu zaznaczenia na menu poza ekran. Aby to osiągnąć, ustawiam przejście widoczności, gdy zmienia się :target.

  • Gdy wchodzę w element, nie przechodź do niego płynnie. Element powinien być widoczny od razu, abym mógł zobaczyć, jak się przesuwa i przejmuje fokus.
  • Podczas wychodzenia z okna widoczność zmienia się, ale z opóźnieniem, dzięki czemu na końcu przechodzi w stan hidden.

Ulepszenia wrażeń użytkownika związanych z ułatwieniami dostępu

To rozwiązanie polega na zmianie adresu URL w celu zarządzania stanem. Oczywiście w tym przypadku należy użyć elementu <a>, który bezpłatnie zapewnia przydatne funkcje ułatwień dostępu. Oznaczmy nasze elementy interaktywne etykietami, które jasno określają ich przeznaczenie.

<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu"></a>

<a href="#sidenav-open" id="sidenav-button" class="hamburger" title="Open Menu" aria-label="Open Menu">
  <svg>...</svg>
</a>
Demo interfejsu użytkownika dotyczącego lektora i interakcji z klawiaturą.

Teraz nasze główne przyciski interakcji wyraźnie określają swoje przeznaczenie zarówno w przypadku myszy, jak i klawiatury.

:is(:hover, :focus)

Ten przydatny funkcjonalny pseudoselektor CSS pozwala nam szybko stosować style najechania kursorem, udostępniając je również w przypadku najechania kursorem.

.hamburger:is(:hover, :focus) svg > line {
  stroke: hsl(var(--brandHSL));
}

Rozsypka w JavaScript

Aby zamknąć, naciśnij escape

Przycisk Escape na klawiaturze powinien zamknąć menu. Podłączmy to.

const sidenav = document.querySelector('#sidenav-open');

sidenav.addEventListener('keyup', event => {
  if (event.code === 'Escape') document.location.hash = '';
});
Historia przeglądarki

Aby zapobiegać gromadzeniu się wielu wpisów w historii przeglądarki w przypadku interakcji otwierania i zamykania, dodaj do przycisku Zamknij następujący kod JavaScript:

<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu" onchange="history.go(-1)"></a>

Spowoduje to usunięcie wpisu z historii adresów URL po zamknięciu menu, co sprawi, że będzie wyglądać tak, jakby menu nigdy nie zostało otwarte.

Focus UX

Następny fragment kodu pomaga nam ustawić fokus na przyciskach otwierania i zamykania po ich otwarciu lub zamknięciu. Chcę, aby przełączanie było łatwe.

sidenav.addEventListener('transitionend', e => {
  const isOpen = document.location.hash === '#sidenav-open';

  isOpen
      ? document.querySelector('#sidenav-close').focus()
      : document.querySelector('#sidenav-button').focus();
})

Gdy otworzy się pasek boczny, ustaw fokus na przycisku Zamknij. Gdy pasek boczny się zamknie, ustaw fokus na przycisku Otwórz. Aby to zrobić, wywołuję funkcję focus() elementu w JavaScript.

Podsumowanie

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

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