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.
Taktyki internetowe
W tej eksploracji komponentów połączyłem kilka kluczowych funkcji platformy internetowej:
- CSS
:target
- siatka w CSS,
- przekształcenia w CSS,
- Zapytania multimedialne CSS dotyczące widocznego obszaru i preferencji użytkownika
- 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;
}
}
Tłoko menu
<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 2fr
i 1fr
, aby znaleźć odpowiedni stosunek dla menu i przycisku Zamknij.
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;
}
}
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
Linki
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>
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
- @_developit z elementami niestandardowymi: demo i kod
- @mayeedwin1 z HTML/CSS/JS: demo i kod
- @a_nurella z Glitch Remix: demo i kod
- @EvroMalarkey z HTML/CSS/JS: demo i kod