Codelab: creazione di un componente di Barra di navigazione laterale

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

Leggi il mio post del blog Building a Sidenav component per scoprire le funzionalità della piattaforma web CSS scelte per la creazione di questo componente.

Configurazione

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

HTML

Innanzitutto, configura l'HTML di base in modo da avere contenuti e alcune caselle con cui lavorare.

Inserisci il seguente codice HTML nel tag <body>.

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

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

Successivamente, riempiremo 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 perfetti all'interno degli elementi <nav> e gli elementi <nav> sono perfetti nelle barre laterali <aside>. Tuttavia, possiamo fare di più per migliorare.

Nell'elemento dei contenuti principali, 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. Il riquadro laterale contiene il pulsante di chiusura. A breve mostreremo e nasconderemo gli elementi in base alle dimensioni della finestra.

Nell'elemento <article>, abbiamo incollato una frase segnaposto. Sostituisci `` con i tuoi contenuti o incolla il testo 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. È un codice pulito, semantico e già piuttosto senza tempo, ma possiamo renderlo più pulito e chiaro per tutti. Il link aperto nel riquadro di navigazione potrebbe essere contrassegnato in modo più chiaro.

Aggiungi gli attributi title e aria-label all'elemento di apertura del link dell'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 all'SVG all'interno dell'elemento di apertura del link:

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

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

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

CSS

È il momento di disporre gli elementi. I contenuti principali e la barra di navigazione laterale sono elementi secondari diretti del tag <body>, quindi è un buon punto di partenza.

Aggiungi il seguente CSS a 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;
    }
  }
}

Questo layout indica essenzialmente: crea una riga denominata stack con tutto il suo contenuto e due colonne in quella riga, la seconda delle quali è denominata anche stack. La prima colonna deve essere dimensionata in base alle esigenze minime di contenuti, mentre la seconda può occupare il resto. Poi, se in un'area visibile vincolata di 540px o meno, inserisci gli elementi della barra di navigazione laterale e dei contenuti principali nella stessa riga e colonna, in modo che siano uno sopra l'altro in una griglia 1x1.

Con questa funzionalità di impilamento reattivo come base, ora possiamo sfruttare lo stato della barra degli URL per attivare/disattivare la visibilità e lo stile di transizione della barra di navigazione laterale.

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

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

In questo modo, il CSS può 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 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">

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

In questo modo si conclude il layout di impilamento reattivo della macro <body>, che ci collega alla barra degli URL. Continuiamo così.

Anche il <aside> ha un layout ordinato. Ha due elementi secondari: un elemento <nav>, che è il componente simile a un foglio di carta che scorre verso l'esterno, e un elemento di collegamento <a> di chiusura che imposta l'URL su #. Il link è invisibile a destra della barra di navigazione a scorrimento della pagina, in modo che gli utenti possano "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 pensato che il rapporto e i nomi fossero un tocco davvero piacevole, in cui la griglia poteva brillare e dare a un designer molto controllo.

Successivamente, devo sovrapporre in modo condizionale i contenuti principali e mantenere la mia posizione durante 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 abbia l'altezza dell'area visibile, scorra verticalmente e contenga lo scorrimento. Ancora più importante, nasconde l'elemento. Per impostazione predefinita, quando la visualizzazione è 540px o più piccola, 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 di questo elemento e la barra degli URL sono uguali, imposta visibility su visible. Apri il menu laterale dopo aver scorri la pagina o prova a scorrere la pagina mentre la barra di navigazione laterale è aperta. Cosa ne pensi?

Aggiungi il seguente CSS alla fine di 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 nostri pulsanti di apertura e chiusura, specificano gli stili di tocco e tocco prolungato e li nascondono anche quando le finestre vengono visualizzate a 540px o più.

Per un tocco di stile, 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 media query `prefers-reduced-motion`.

Aggiungere un po' di JavaScript

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

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

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

Questo ascolta un evento chiave sull'elemento della barra di navigazione laterale. Se è Escape, l'hash dell'URL viene impostato su vuoto, in modo che la transizione della barra di navigazione laterale venga eseguita.

Il successivo elemento di UX JS è la gestione della messa a fuoco. Voglio semplificare l'apertura e la chiusura, quindi aspetto che la barra di navigazione laterale abbia completato una transizione di qualche tipo, poi la controllo rispetto all'hash dell'URL per determinare se è dentro o fuori. Poi utilizzo JavaScript per impostare lo stato attivo sul pulsante complementare a quello appena premuto.

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 premi Schermo intero schermo intero.

Conclusione

Questo è tutto ciò che mi serviva per il componente. Puoi basarti su questo codice, gestirlo con lo stato JavaScript anziché con l'URL e, in generale, personalizzarlo come preferisci. C'è sempre qualcosa da aggiungere o altri casi d'uso da trattare.

Apri css/brandnav.css per visualizzare gli stili non correlati al layout che ho applicato a questo componente. Non lo ritenevo importante per il set di funzionalità su cui mi stavo concentrando e speravo che la separazione degli stili dal layout avrebbe incoraggiato il copia e incolla. Potresti trovare altre informazioni utili.

Come si creano componenti di navigazione laterale adattabili a comparsa? Ne hai mai più di uno, ad esempio uno su ogni lato? Mi piacerebbe inserire la tua soluzione in un video di YouTube, assicurati di taggarmi su Twitter o di commentare su YouTube con il tuo codice. Aiuterà tutti gli utenti.