Creazione di un componente di navigazione laterale

Una panoramica di base su come creare una navigazione laterale reattiva con slide

In questo post voglio condividere con voi come ho prototipato un componente di navigazione laterale per il web che è reattivo, stateful, supporta la navigazione da tastiera, funziona con e senza JavaScript, e funziona su tutti i browser. Prova la demo.

Se preferisci i video, ecco una versione di questo post su YouTube:

Panoramica

È difficile creare un sistema di navigazione reattivo. Alcuni utenti usano una tastiera, altre dispongono di desktop potenti e altre ancora da un piccolo dispositivo mobile. Chiunque visiti il tuo sito dovrebbe essere in grado di aprire e chiudere il menu.

Demo del layout reattivo da computer a dispositivo mobile
Tema chiaro e scuro disattivato su iOS e Android

Tattiche sul web

In questa esplorazione dei componenti ho avuto la gioia di combinare alcune funzionalità fondamentali della piattaforma web:

  1. Servizio di shopping comparativo :target
  2. Griglia CSS
  3. CSS trasforma
  4. Query multimediali CSS per area visibile e preferenza dell'utente
  5. JS per focus miglioramenti dell'esperienza utente

La mia soluzione ha una barra laterale e attiva/disattiva solo quando si trova su un dispositivo mobile area visibile di 540px o inferiore. 540px sarà il nostro punto di interruzione per passare dal layout interattivo mobile a quello statico per computer e viceversa.

Pseudo-classe :target CSS

Un link <a> imposta l'hash dell'URL su #sidenav-open e l'altro su vuoto (''). Infine, un elemento ha id per corrispondere all'hash:

<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>

Facendo clic su ciascuno di questi link viene modificato lo stato hash dell'URL della nostra pagina. quindi con una pseudo-classe mostro e nascono la barra laterale:

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

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

Griglia CSS

In passato, utilizzavo solo la posizione assoluta o fissa layout e componenti della navigazione laterale. La griglia però, con la sua sintassi grid-area, consente di assegnare più elementi alla stessa riga o colonna.

Impilati

L'elemento di layout principale #sidenav-container è una griglia che crea una riga e due colonne, 1 di ognuno ha il nome stack. Quando lo spazio è vincolato, il CSS assegna tutti gli elementi dell'elemento <main> secondari con lo stesso nome della griglia, posizionando tutti gli elementi nello stesso spazio, creando una pila.

#sidenav-container {
  display: grid;
  grid: [stack] 1fr / min-content [stack] 1fr;
  min-height: 100vh;
}

@media (max-width: 540px) {
  #sidenav-container > * {
    grid-area: stack;
  }
}

<aside> è l'elemento animato che contiene la barra di navigazione laterale. Ha 2 elementi secondari: il contenitore di navigazione <nav> denominato [nav] e uno sfondo <a> denominato [escape], che viene utilizzato per chiudere il menu.

#sidenav-open {
  display: grid;
  grid-template-columns: [nav] 2fr [escape] 1fr;
}

Modifica 2fr e 1fr per trovare le proporzioni che preferisci per l'overlay del menu e il relativo pulsante di chiusura dello spazio negativo.

Una demo di ciò che succede quando modifichi le proporzioni.

Trasformazioni 3D CSS e transizioni

Il nostro layout è ora impilato con dimensioni dell'area visibile su dispositivi mobili. Finché non aggiungo nuovi stili, si sovrappone al nostro articolo per impostazione predefinita. Ecco alcune UX che cercherò nella prossima sezione:

  • Anima apertura e chiusura
  • L'animazione con il movimento viene eseguita solo se l'utente è d'accordo.
  • Attiva l'animazione visibility in modo che lo stato attivo della tastiera non entri nell'elemento fuori schermo

Man mano che inizio a implementare le animazioni di movimento, voglio partire con la massima priorità sull'accessibilità.

Movimenti accessibili

Non a tutti vorranno provare l'esperienza di movimento. Nella nostra soluzione, questa preferenza viene applicata regolando una variabile CSS --duration all'interno di una query multimediale. Questo valore di query supporti rappresenta alle preferenze del sistema operativo di un utente per il movimento (se disponibile).

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

@media (prefers-reduced-motion: reduce) {
  #sidenav-open {
    --duration: 1ms;
  }
}
Una demo dell'interazione con e senza durata applicata.

Ora, quando la barra di navigazione laterale scorre aperta e chiusa, se un utente preferisce movimento ridotto, Sposto immediatamente l'elemento in vista, mantenendo lo stato senza movimento.

Transizione, trasformazione e traslazione

Navigazione laterale in uscita (predefinita)

Per impostare lo stato predefinito della nostra navigazione laterale sui dispositivi mobili su uno stato fuori schermo: posiziono l'elemento con transform: translateX(-110vw).

Tieni presente che ho aggiunto un altro 10vw al codice tipico fuori schermo di -100vw, per assicurarti che box-shadow della barra di navigazione laterale non sblocchi nell'area visibile principale quando è nascosta.

@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);
  }
}
Navigazione laterale in

Quando l'elemento #sidenav corrisponde a :target, imposta la posizione translateX() su base 0, e osserva come CSS fa scorrere l'elemento dalla posizione di uscita -110vw alla posizione "in" posizione di 0 su var(--duration) quando l'hash dell'URL viene modificato.

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

Visibilità delle transizioni

Ora l'obiettivo è nascondere il menu agli screen reader quando è disattivato. in modo che i sistemi non mettano lo stato in evidenza su un menu fuori schermo. A tal fine, imposto un transizione alla visibilità quando cambia il valore :target.

  • Quando entri, non cambiare la visibilità; saranno visibili subito, così posso vedere l'elemento scorrere e accettare lo stato attivo.
  • Quando esci, la visibilità delle transizioni è ritardata, quindi al termine dell'uscita il passaggio passa a hidden.

Miglioramenti dell'esperienza utente per l'accessibilità

Questa soluzione si basa sulla modifica dell'URL per la gestione dello stato. Ovviamente, l'elemento <a> dovrebbe essere usato qui e ha una buona accessibilità funzioni senza costi. Adoriamo i nostri elementi interattivi con etichette che indicano chiaramente le intenzioni degli utenti.

<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>
Una demo dell'esperienza utente con la voce fuori campo e l'interazione con la tastiera.

Ora i nostri pulsanti di interazione principali indicano chiaramente il loro intento sia per il mouse che per la tastiera.

:is(:hover, :focus)

Questo pratico pseudo-selettore funzionale CSS ci consente di essere rapidamente inclusivi con i nostri stili al passaggio del mouse condividendoli con lo stato attivo.

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

Aggiungi elementi su JavaScript

Premi escape per chiudere

Il tasto Escape sulla tastiera dovrebbe chiudere il menu. Colleghiamolo.

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

sidenav.addEventListener('keyup', event => {
  if (event.code === 'Escape') document.location.hash = '';
});
Cronologia del browser

Per evitare che le interazioni di apertura e chiusura si sovrappongano più voci nella cronologia del browser, aggiungi il seguente codice JavaScript in linea pulsante di chiusura:

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

La voce della cronologia degli URL verrà rimossa alla chiusura, creando così come se il menu fosse mai aperto.

Concentrati sull'esperienza utente

Lo snippet successivo ci aiuta a mettere in risalto i pulsanti di apertura e chiusura dopo si aprono o si chiudono. Voglio semplificare l'attivazione/disattivazione.

sidenav.addEventListener('transitionend', e => {
  const isOpen = document.location.hash === '#sidenav-open';

  isOpen
      ? document.querySelector('#sidenav-close').focus()
      : document.querySelector('#sidenav-button').focus();
})

Quando si apre la barra di navigazione laterale, imposta lo stato attivo sul pulsante di chiusura. Quando la barra di navigazione laterale si chiude, imposta lo stato attivo sul pulsante di apertura. Per farlo, richiamo focus() sull'elemento in JavaScript.

Conclusione

Ora che sai come ci ho fatto, come lo faresti?! Ciò rende l'architettura dei componenti divertente. Chi produrrà la prima versione con gli slot? 🙂

Diversifica il nostro e scoprire tutti i modi per creare sul web. Crea un Glitch. invia un tweet alla tua versione e la aggiungerò al Sezione Remix della community di seguito.

Remix della community