Codelab: creazione di un componente di Barra di navigazione laterale

Questo codelab ti insegna come creare un componente di layout di navigazione laterale a scorrimento adattabile sul web. Creeremo il componente man mano che procediamo, iniziando con HTML, poi CSS, poi JavaScript.

Consulta il mio post del blog Creazione di un componente Sidenav per scoprire le funzionalità della piattaforma web CSS scelte per la creazione di questo componente.

Configurazione

  1. Fai clic su Remix per modificare per rendere il progetto modificabile.
  2. Apri app/index.html.

HTML

Innanzitutto, ottieni gli elementi essenziali della configurazione HTML in modo che ci siano contenuti e alcune caselle con cui lavorare.

Trascina il seguente codice HTML nel tag <body>.

<aside></aside>
<main></main>

L'elemento <aside> contiene il menu di navigazione come elemento complementare di <main>, che contiene i contenuti principali della pagina.

Successivamente, completeremo questi elementi semantici con il resto dei contenuti della pagina.

Aggiungi un elemento di navigazione, alcuni link di navigazione e un link di chiusura all'interno dell'elemento <aside>.

<aside>
  <nav>
    <h4>My</h4>
    <a href="#">Dashboard</a>
    <a href="#">Profile</a>
    <a href="#">Preferences</a>
    <a href="#">Archive</a>

    <h4>Settings</h4>
    <a href="#">Accessibility</a>
    <a href="#">Theme</a>
    <a href="#">Admin</a>
  </nav>

  <a href="#"></a>
</aside>

I link sono molto utili all'interno degli elementi <nav>, mentre quelli <nav> sono ideali nelle barre laterali <aside>. Tuttavia, c'è altro che possiamo fare per migliorare.

Nell'elemento dei contenuti principale, aggiungi un'intestazione e un articolo per contenere semanticamente i contenuti del layout.

<main>
  <header>
    <a href="#sidenav-open" class="hamburger">
      <svg viewBox="0 0 50 40">
        <line x1="0" x2="100%" y1="10%" y2="10%" />
        <line x1="0" x2="100%" y1="50%" y2="50%" />
        <line x1="0" x2="100%" y1="90%" y2="90%" />
      </svg>
    </a>
    <h1>Site Title</h1>
  </header>

  <article>
    {put some placeholder content here}
  </article>
</main>

L'intestazione contiene il link per aprire il menu. Sull'altro c'è il pulsante di chiusura. A breve mostreremo e nasconderemo gli elementi in base alle dimensioni dell'area visibile.

Nell'elemento <article>, abbiamo incollato una frase segnaposto. Sostituisci "` con i tuoi contenuti o incolla il lorem fornito di seguito:

<h2>Totam Header</h2>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Cum consectetur, necessitatibus velit officia ut impedit veritatis temporibus soluta? Totam odit cupiditate facilis nisi sunt hic necessitatibus voluptatem nihil doloribus! Enim.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>

<h3>Subhead Totam Odit</h3>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>

<h3>Subhead</h3>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>

Questi contenuti e la loro lunghezza sono ciò che farà scorrere la pagina quando supera l'altezza dell'area visibile.

Finora hai aggiunto un elemento Aside, con una barra di navigazione, link e un modo per chiudere la barra di navigazione laterale. Hai anche aggiunto un'intestazione, un modo per aprire la barra di navigazione laterale e un articolo all'elemento principale. È già chiaro, semantico e senza tempo, ma possiamo renderlo più chiaro e chiaro per tutti. Il link aperto nella barra di navigazione laterale potrebbe essere contrassegnato in modo più chiaro.

Aggiungi gli attributi title e aria-label all'elemento link aperto con intestazione:

<a href="#sidenav-open" class="hamburger">
<a href="#sidenav-open" title="Open Menu" aria-label="Open Menu" class="hamburger">

Anche l'icona SVG aperta potrebbe essere contrassegnata in modo più chiaro. Aggiungi i seguenti attributi al file SVG all'interno dell'elemento link aperto:

<svg viewBox="0 0 50 40">
<svg viewBox="0 0 50 40" role="presentation" focusable="false" aria-label="trigram for heaven symbol">

Il link vicino nella barra di navigazione laterale potrebbe essere contrassegnato in modo più chiaro. Aggiungi gli attributi title e aria-label all'elemento link di chiusura della navigazione laterale:

<a href="#"></a>
<a href="#" title="Close Menu" aria-label="Close Menu"></a>

CSS

È il momento di definire il layout degli elementi. I contenuti principali e la barra di navigazione laterale sono elementi secondari diretti del tag <body>, perciò è un buon punto di partenza.

Aggiungi il seguente CSS in css/sidenav.css in modo che l'elemento <body> disponga gli elementi secondari.

body {
  display: grid;
  grid: [stack] 1fr / min-content [stack] 1fr;

  @media (max-width: 540px) {
    & > :matches(aside, main) {
      grid-area: stack;
    }
  }
}

In sostanza, questo layout dice: Crea una riga denominata stack che contenga tutti i contenuti e 2 colonne in quella riga, la seconda delle quali è denominata stack. La prima colonna deve essere dimensionata in base alle esigenze minime di contenuti, la seconda colonna può occupare il resto. Poi, se in un'area visibile vincolata pari o inferiore a 540px, inserisci gli elementi della barra di navigazione laterale e dei contenuti principali nella stessa riga e nella stessa colonna, in modo che siano uno sopra l'altro in una griglia 1 x 1.

Grazie a questa funzionalità di stack reattiva come base, ora possiamo sfruttare lo stato della barra degli URL per attivare/disattivare lo stile di visibilità e transizione della barra di navigazione laterale.

Aggiorna l'elemento <aside> di nuovo in app/index.html:

<aside>
<aside id="sidenav-open">

In questo modo, il CSS potrà abbinare un elemento e l'hash dell'URL. Questo è importante per l'utilizzo di :target. Ora l'ID dell'elemento può corrispondere all'hash dell'URL che imposteremo con i tag <a>.

Inoltre, per semplificare il targeting JavaScript, aggiungi gli ID per gli elementi chiave che controllano la barra di navigazione laterale. Innanzitutto, aggiungi un ID al link di apertura della barra di navigazione laterale:

<a href="#sidenav-open" class="hamburger" title="Open Menu" aria-label="Open Menu">
<a href="#sidenav-open" id="sidenav-button" class="hamburger" title="Open Menu" aria-label="Open Menu">

Poi, aggiungi un ID al link di chiusura della barra di navigazione laterale:

<a href="#" title="Close Menu" aria-label="Close Menu"></a>
<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu"></a>

Questo conclude il layout della macro <body> in pila adattabile e ci collega alla barra dell'URL. Andiamo avanti!

Anche <aside> ha un layout curato. Ha 2 elementi secondari, uno <nav>, che è il componente simile alla carta che scorre fuori, e un elemento link <a> di chiusura che imposta l'URL su #. Il link non è visibile sulla destra del riquadro di navigazione a scorrimento, pertanto gli utenti possono "fare clic" sul componente visivo per chiuderlo.

Aggiungi il seguente CSS a css/sidenav.css:

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

Ho trovato le proporzioni e i nomi che erano molto belli, in cui la griglia poteva risaltare e dare al designer molto controllo.

Poi devo sovrapporre i contenuti principali in modo condizionale e mantenere la posizione attraverso lo scorrimento del documento. Questo è un ottimo lavoro per position: sticky e alcuni overscroll-behavior.

Aggiungi i seguenti stili per la barra di navigazione laterale:

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

  @media (max-width: 540px) {
    position: sticky;
    top: 0;
    max-height: 100vh;
    overflow: hidden auto;
    overscroll-behavior: contain;

    visibility: hidden; /* not keyboard accessible when closed */
  }
}

Questi stili assicurano che la barra di navigazione laterale corrisponda all'altezza dell'area visibile, scorra verticalmente e contenga lo scorrimento. Ma soprattutto, nasconde l'elemento. Per impostazione predefinita, quando l'area visibile è pari o inferiore a 540px, nascondi la barra di navigazione laterale. A meno che!

Aggiungi uno pseudo-selettore :target all'elemento #sidenav-open:

#sidenav-open {

  @media (max-width: 540px) {

    &:target {
      visibility: visible;
    }
  }
}

Se l'ID dell'elemento e la barra dell'URL sono uguali, imposta visibility su visible. Apri il menu laterale dopo aver fatto scorrere la pagina oppure prova a scorrere la pagina mentre è aperta. Cosa ne pensi?

Aggiungi il seguente CSS in fondo a app/sidenav.css:

#sidenav-button,
#sidenav-close {
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  user-select: none;
  touch-action: manipulation;

  @media (min-width: 540px) {
    display: none;
  }
}

Questi stili hanno come target i pulsanti di apertura e chiusura, ne specificano gli stili tocco e tocco e li nascondono anche quando le aree visibili sono pari o superiori a 540px.

Per un tocco di classe, aggiungiamo trasformazioni CSS con un'accessibilità rispettosa. Aggiungi il seguente CSS a css/sidenav.css:

#sidenav-open {
  --easeOutExpo: cubic-bezier(0.16, 1, 0.3, 1);
  --duration: .6s;

  ...

  @media (max-width: 540px) {
    ...

    transform: translateX(-110vw);
    will-change: transform;
    transition:
      transform var(--duration) var(--easeOutExpo),
      visibility 0s linear var(--duration);

    &:target {
      visibility: visible;
      transform: translateX(0);
      transition: transform var(--duration) var(--easeOutExpo);
    }
  }

  @media (prefers-reduced-motion: reduce) {
    --duration: 1ms;
  }
}
Una demo dell'interazione con e senza durata applicata in base alla query multimediale "prefers-reduced-motion".

Aggiungi codice JavaScript

Il tasto Escape dovrebbe chiudere il menu. Aggiungi questo codice JS a js/index.js:

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

sidenav.addEventListener('keyup', e => {
  if (e.code === 'Escape') {
    document.location.hash = '';
  }
});

Questo rimane in ascolto di un evento chiave nell'elemento sidenav. Se è Escape, l'hash dell'URL viene impostato su vuoto e viene eseguita la transizione della barra di navigazione laterale.

Il prossimo aspetto dell'UX JS riguarda la gestione delle aree di interesse. Voglio semplificare l'apertura e la chiusura, quindi aspetto fino al termine della transizione della barra di navigazione laterale, quindi esegui un controllo incrociato con l'hash dell'URL per determinare se è in entrata o in uscita. Uso JavaScript per impostare lo stato attivo sul pulsante complementare.

Aggiungi il seguente codice JavaScript a js/index.js:

const closenav = document.querySelector('#sidenav-close');
const opennav = document.querySelector('#sidenav-button');

sidenav.addEventListener('transitionend', e => {
  if (e.propertyName !== 'transform') {
    return;
  }

  const isOpen = document.location.hash === '#sidenav-open';

  isOpen
    ? closenav.focus()
    : opennav.focus();
});

Prova

  • Per visualizzare l'anteprima del sito, premi Visualizza app, quindi Schermo intero schermo intero.

Conclusione

Questa è la conclusione per le mie esigenze legate al componente. Puoi basarci su questo approccio, usalo con lo stato JavaScript anziché l'URL e, in generale, rendilo tuo. Ci sono sempre più contenuti da aggiungere o più casi d'uso da trattare.

Apri css/brandnav.css per controllare gli stili non correlati al layout che ho applicato a questo componente. Non pensavo fosse importante per il set di funzionalità su cui mi concentravo e speravo che separare gli stili dal layout avrebbe incoraggiato il copia e incolla. Potrebbe esserci altro ancora da imparare.

Come fai a scorrere i componenti di navigazione laterale adattabili? Ne hai mai uno su entrambi i lati, ad esempio uno? Mi piacerebbe presentare la tua soluzione in un video di YouTube. Assicurati di inviarmi un tweet o di lasciare un commento su YouTube con il tuo codice, così sarà d'aiuto a tutti.