Podstawowy przegląd tworzenia elastycznego paska bocznego z przesuwnym menu
W tym poście opowiem, jak udało mi się stworzyć prototypowy komponent Sidenav dla stron internetowych. Jest elastyczny, stanowy, obsługuje nawigację za pomocą klawiatury, obsługuje JavaScript i bez niego oraz działa w różnych przeglądarkach. Zobacz prezentację.
Jeśli wolisz film, oto wersja tego posta w YouTube:
Omówienie
Budowanie elastycznego systemu nawigacji jest trudne. Niektórzy będą korzystać z klawiatury, inni z wydajnymi komputerami, a inni korzystają z małych urządzeń mobilnych. 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
ulepszania UX
Moje rozwiązanie ma 1 pasek boczny i przełącza się tylko w widoku na urządzenia mobilne, który wynosi 540px
lub mniej.
540px
będzie naszym punktem przerwania przy przełączaniu między interaktywnym układem na urządzenia mobilne a statycznym układem na komputery.
Pseudoklasa usługi porównywania cen :target
Jeden link <a>
ustawia skrót 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, który zawiera boczne elementy nawigacyjne. 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 nakładki i przycisku zamknięcia w pustej przestrzeni.
Przekształcenia i przejścia 3D w CSS
Układ jest teraz ułożony w wielkości widocznego obszaru na urządzeniu mobilnym. Dopóki nie dodam nowych stylów, będą one domyślnie nakładane na nasz artykuł. W następnej sekcji pokażę, jak zwiększyć wygodę użytkowników.
- Animowanie otwierania i zamykania
- Animuj z ruchem 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 każdemu przydałaby się ruchoma wysuwana reklama. W naszym rozwiązaniu to ustawienie jest stosowane przez dostosowanie zmiennej CSS --duration
w zapytaniu o media. 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 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
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. Jestem w tym celu ustawiany przez ustawienie
widoczności w przypadku zmiany :target
.
- Gdy wchodzę w element, nie przechodź do niego przez przejście. Element powinien być widoczny od razu, abym mógł zobaczyć, jak się pojawia i przejmuje fokus.
- Podczas wychodzenia z okna widoczność przechodzi w tryb widoczny, ale z opóźnieniem, dzięki czemu na końcu okna jest ona ustawiona na
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 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));
}
Dodawanie elementów JavaScript
Aby zamknąć, naciśnij escape
Przycisk Escape
na klawiaturze powinien zamknąć menu. Zaczynajmy.
const sidenav = document.querySelector('#sidenav-open');
sidenav.addEventListener('keyup', event => {
if (event.code === 'Escape') document.location.hash = '';
});
Historia przeglądarki
Aby zapobiec nagromadzeniu 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, tak jakby menu nigdy nie było otwierane.
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
Skoro już wiesz, jak to robię, jak Ty?! To tworzy ciekawą architekturę komponentów. Kto ma utworzyć pierwszą wersję z miejscami? 🙂
Wybierzmy różne podejścia i poznajmy sposoby budowania obecności w internecie. Utwórz glitch, napisz do mnie swoją wersję, a dodam ją do sekcji Remiksy społeczności poniżej.
Remiksy utworzone przez społeczność
- @_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