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.
Taktyki internetowe
Podczas tworzenia tego komponentu miałem przyjemność połączyć kilka kluczowych funkcji platformy internetowej:
- CSS
:target
- Siatka CSS
- przekształcenia CSS,
- Zapytania o multimedia CSS dotyczące widocznego obszaru i preferencji użytkownika
- 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;
}
}
Tło menu
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 2fr
i 1fr
, aby znaleźć odpowiedni stosunek dla nakładki menu i przycisku zamykania.
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;
}
}
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
Linki
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>
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
- @_developit z elementami niestandardowymi: wersja demonstracyjna i kod
- @mayeedwin1 z HTML/CSS/JS: demo i kod
- @a_nurella z remiksem Glitch: wersja demonstracyjna i kod
- @EvroMalarkey z HTML/CSS/JS: demo i kod