Tworzenie komponentu bocznego

Podstawowe informacje o tym, jak utworzyć elastyczny wysuwany panel boczny

W tym poście chcę Ci pokazać, jak stworzyłem prototyp komponentu Sidenav na potrzeby internetu, który jest responsywny, ma stan, obsługuje nawigację za pomocą klawiatury, działa z JavaScriptem i bez niego oraz jest zgodny z różnymi przeglądarkami. Wypróbuj wersję demonstracyjną.

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

Przegląd

Stworzenie elastycznego systemu nawigacji jest trudne. Niektórzy użytkownicy będą korzystać z klawiatury, inni z wydajnych komputerów, a jeszcze inni z małych urządzeń mobilnych. Każdy użytkownik powinien mieć możliwość otwierania i zamykania menu.

Prezentacja układu responsywnego na urządzeniach mobilnych
Motyw jasny i ciemny na iOS i Androidzie

Taktyki internetowe

Podczas tworzenia tego komponentu miałem przyjemność połączyć kilka kluczowych funkcji platformy internetowej:

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

Moje rozwiązanie ma 1 pasek boczny i przełącza się tylko wtedy, gdy widoczny obszar ma rozmiar 540px lub mniejszy. 540px będzie punktem podziału, w którym przełączymy się z interaktywnego układu na urządzenia mobilne na statyczny układ na komputery.

Pseudoklasa CSS :target

Jeden link <a> ustawia hash adresu URL na #sidenav-open, a drugi na pusty (''). Na koniec element ma atrybut id, który pasuje do hasha:

<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 fragmentu z krzyżykiem w adresie URL strony, a następnie za pomocą pseudoklasy pokazuję i ukrywam panel boczny:

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

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

CSS Grid

W przeszłości używałem tylko układów i komponentów paska bocznego o położeniu bezwzględnym lub stałym. Siatka z syntaktyką grid-area umożliwia przypisywanie wielu elementów do tego samego wiersza lub 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 miejsca jest mało, CSS przypisuje wszystkie elementy podrzędne elementu <main> do tej samej nazwy siatki, umieszczając wszystkie elementy w tym samym miejscu i 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;
  }
}

Element <aside> to animowany element, który zawiera nawigację boczną. Zawiera 2 elementy podrzędne: kontener nawigacji <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 nakładki menu i przycisku zamykania.

Prezentacja tego, co się stanie po zmianie współczynnika.

Przekształcenia i przejścia 3D w CSS

Nasz układ jest teraz ułożony w stos na urządzeniu mobilnym. Until I add some new styles, it's overlaying our article by default. W tej sekcji chcę osiągnąć następujący UX:

  • Animacja otwierania i zamykania
  • Animuj tylko wtedy, gdy użytkownik wyrazi na to zgodę
  • Animuj visibility, aby zaznaczenie klawiatury nie przechodziło do elementu poza ekranem.

Gdy zacznę wdrażać animacje ruchu, chcę przede wszystkim pamiętać o dostępności.

Ruch dostępny

Nie każdy będzie chciał korzystać z funkcji wysuwania. W naszym rozwiązaniu to ustawienie jest stosowane przez dostosowanie zmiennej CSS --duration w zapytaniu o media. Ta wartość zapytania o media reprezentuje preferencje użytkownika dotyczące ruchu w systemie operacyjnym (jeśli są dostępne).

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

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

Gdy panel boczny otwiera się i zamyka, a użytkownik woli ograniczone animacje, natychmiast przenoszę element do widoku, zachowując stan bez animacji.

Przejście, przekształcenie, tłumaczenie

Sidenav out (domyślnie)

Aby ustawić domyślny stan naszego panelu bocznego na urządzeniach mobilnych na stan poza ekranem, umieszczam element za pomocą transform: translateX(-110vw).

Zauważ, że do typowego kodu poza ekranem -100vw dodałem kolejny znak 10vw, aby upewnić się, że element box-shadow paska bocznego nie będzie widoczny w głównym obszarze wyświetlania, gdy będzie ukryty.

@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);
  }
}
Boczny pasek nawigacyjny

Gdy element #sidenav pasuje do :target, ustaw pozycję translateX() na pozycję początkową 0 i obserwuj, jak CSS przesuwa element z pozycji wyjściowej -110vw do pozycji „wejściowej” 0 w ciągu var(--duration), gdy zmieni się hash adresu URL.

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

Widoczność przejścia

Teraz chcemy ukryć menu przed czytnikami ekranu, gdy jest ono niewidoczne, aby systemy nie przenosiły fokusu na menu poza ekranem. Osiągam to, ustawiając przejście widoczności, gdy zmienia się :target.

  • Nie zmieniaj widoczności podczas wchodzenia w interakcję. Element powinien być od razu widoczny, aby można było zobaczyć, jak się pojawia i przejmuje fokus.
  • Podczas wychodzenia zmień widoczność, ale opóźnij ją, aby na końcu przejścia zmieniła się na hidden.

Ulepszenia wrażeń użytkownika w zakresie ułatwień dostępu

To rozwiązanie polega na zmianie adresu URL, aby można było zarządzać stanem. Oczywiście należy tu użyć elementu <a>, który zapewnia bezpłatnie przydatne funkcje ułatwień dostępu. Oznaczmy 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>
Wersja demonstracyjna interfejsu użytkownika z narracją i interakcją z klawiaturą.

Główne przyciski interakcji wyraźnie wskazują teraz swoje przeznaczenie zarówno w przypadku myszy, jak i klawiatury.

:is(:hover, :focus)

Ten przydatny pseudoselektor funkcyjny CSS pozwala nam szybko uwzględnić style najechania kursorem, udostępniając je również dla stanu aktywnego.

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

Dodawanie kodu JavaScript

Naciśnij escape, aby zamknąć

Klawisz Escape na klawiaturze powinien zamknąć menu, prawda? Podłączmy to.

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

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

Aby zapobiec dodawaniu wielu wpisów do historii przeglądarki w wyniku interakcji otwierania i zamykania, dodaj ten kod JavaScript w wierszu do przycisku zamykania:

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

Spowoduje to usunięcie wpisu historii adresu URL po zamknięciu, dzięki czemu będzie wyglądać tak, jakby menu nigdy nie zostało otwarte.

Focus UX

Kolejny fragment kodu pomaga nam skupić się 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 otworzysz panel boczny, ustaw fokus na przycisku zamykania. Gdy menu boczne zostanie zamknięte, fokus zostanie przeniesiony na przycisk otwierania. Aby to zrobić, wywołuję funkcję focus() w elemencie w JavaScript.

Podsumowanie

Teraz, gdy wiesz, jak to zrobiłem, jak Ty byś to zrobił? Dzięki temu architektura komponentów jest ciekawa. Kto stworzy pierwszą wersję z miejscami? 🙂

Urozmaićmy nasze podejście i poznajmy wszystkie sposoby tworzenia stron internetowych. Utwórz Glitch, wyślij mi tweeta z Twoją wersją, a ja dodam ją do sekcji Remiksy społeczności poniżej.

Remiksy społeczności