Tworzenie komponentu bocznego

Podstawowy przegląd tworzenia elastycznego paska bocznego

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 przekształcania układu na potrzeby komputerów stacjonarnych na układ responsywny na urządzenia mobilne
Zmiana motywu na jasny i ciemny 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 jedną stronę boczną i przełączniki tylko w przypadku obszaru widocznego „na urządzeniu mobilnym” o wymiarach 540px lub mniejszych. Punkt graniczny 540px będzie punktem przełączania się między interaktywnym układem na urządzenia mobilne 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 następnie 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 tej samej przestrzeni, 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 nawigacyjny. 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 i przycisku Zamknij.

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:

  • Animacja otwierania i zamykania
  • Animowanie 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 chce ograniczyć 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 do pozycji „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, tak aby na końcu przejścia wartość ta wynosiła 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 należy tu 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 pseudoselektor funkcjonalny CSS pozwala nam szybko udostępniać style najechania kursorem, stosując je również do stanu najechania.

.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ępujący fragment kodu pomaga nam ustawić fokus na przyciskach otwierania i zamykania po ich otwarciu lub zamknięciu. Chcę ułatwić przełączanie.

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óżnicuj swoje podejścia i poznaj 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.

Remiksy społeczności