Codelab: creazione di un componente di Barra di navigazione laterale

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

Dai un'occhiata al mio post del blog Creare 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, acquisisci le nozioni di base della configurazione HTML 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 della pagina principale.

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

Nell'elemento di contenuto 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. Il riquadro contiene il pulsante di chiusura. A breve mostreremo e nasconderemo gli elementi in base alle dimensioni del viewport.

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 fanno sì che la pagina sia scorrevole quando supera l'altezza dell'area visibile.

Finora hai aggiunto un elemento aside, con un menu di navigazione, link e un modo per chiudere il riquadro di navigazione laterale. Hai anche aggiunto un'intestazione, un modo per aprire il riquadro laterale e un articolo all'elemento principale. È già pulito, semantico e piuttosto senza tempo, ma possiamo renderlo più pulito e chiaro per tutti. Il link aperto nel riquadro laterale potrebbe essere contrassegnato in modo più chiaro.

Aggiungi gli attributi title e aria-label all'elemento link di apertura 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'elemento 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 di chiusura nel riquadro laterale potrebbe essere contrassegnato in modo più chiaro. Aggiungi gli attributi title e aria-label all'elemento link di chiusura del riquadro 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 il riquadro 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 tutti gli elementi al suo interno e due colonne in quella riga, la seconda delle quali è denominata anche stack. La prima colonna deve essere dimensionata in base alle esigenze minime dei contenuti e la seconda colonna può occupare il resto. Se l'area visibile è limitata a 540px o meno, inserisci il riquadro laterale e gli elementi dei contenuti principali nella stessa riga e colonna, in modo che si sovrappongano in una griglia 1x1.

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

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

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

In questo modo, il CSS può associare 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 il riquadro laterale. Innanzitutto, aggiungi un ID al link di apertura del riquadro 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">

Aggiungi un ID al link di chiusura del riquadro 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 è il layout di impilaggio responsive della macro <body>, che ci collega alla barra degli URL. Andiamo avanti.

Anche il <aside> ha un layout pulito. Ha due elementi secondari, un <nav>, ovvero il componente simile a un foglio di carta che si estrae, e un elemento link di chiusura <a> che imposta l'URL su #. Il link è invisibile a destra del menu a scomparsa di Carta; in questo modo gli utenti possono fare clic sul componente visivo per ignorarlo.

Aggiungi il seguente CSS a css/sidenav.css:

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

Il rapporto e i nomi sono stati un tocco davvero piacevole, in cui la griglia poteva dare il meglio di sé e offrire al designer un grande controllo.

Successivamente, devo sovrapporre condizionalmente i contenuti principali e mantenere la mia posizione durante lo scorrimento del documento. È un'ottima opportunità per position: sticky e alcuni overscroll-behavior.

Aggiungi i seguenti stili per il riquadro 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 laterale abbia l'altezza dell'area visibile, scorra verticalmente e contenga lo scorrimento. Molto importante, nasconde l'elemento. Per impostazione predefinita, nasconde il riquadro laterale quando l'area visibile è pari o inferiore a 540px. A meno che!

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

#sidenav-open {

  @media (max-width: 540px) {

    &:target {
      visibility: visible;
    }
  }
}

Quando l'ID dell'elemento e della barra degli URL sono uguali, imposta visibility su visible. Apri il menu laterale dopo aver scorruto la pagina o prova a scorrere la pagina con il riquadro laterale aperto. Cosa ne pensi?

Aggiungi il seguente CSS alla parte inferiore 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, ne specificano gli stili di tocco e tap e li nascondono anche quando le visualizzazioni sono pari o superiori a 540px.

Per un tocco in più, aggiungiamo le 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 applicazione della durata in base alla query sui contenuti multimediali "prefers-reduced-motion".

Aggiungi un po' di 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 ascolta un evento chiave nell'elemento sidenav. Se è Escape, l'hash dell'URL viene impostato su vuoto, facendo uscire la transizione del riquadro laterale.

Questo altro componente di UX JS è la gestione dell'attenzione. Voglio semplificare l'apertura e la chiusura, quindi aspetto fino a quando il riquadro laterale non ha completato una transizione di qualche tipo, poi lo controllo con l'hash dell'URL per determinare se è attivo o meno. Poi utilizzo JavaScript per impostare il focus 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 A schermo intero schermo intero.

Conclusione

Ecco un riepilogo delle mie esigenze relative al componente. Non esitare a svilupparlo, a gestirlo con lo stato JavaScript anziché con l'URL e, in generale, a personalizzarlo. C'è sempre qualcosa da aggiungere o più casi d'uso da coprire.

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

Come creare componenti sidenav adattabili scorrevoli? Hai mai più di 1, ad esempio una su entrambi i lati? Mi piacerebbe mostrare la tua soluzione in un video di YouTube. Assicurati di inviarmi un tweet o di commentare su YouTube con il tuo codice, sarà di aiuto a tutti.