Creazione di un componente breadcrumb

Una panoramica di base su come creare un componente di breadcrumb reattivo e accessibile per consentire agli utenti di navigare sul tuo sito.

In questo post voglio parlare di un modo per creare componenti dei breadcrumb. Prova la demo.

Demo

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

Panoramica

Un componente breadcrumb mostra in che punto della gerarchia del sito si trova l'utente. Il nome è Hansel e Gretel, che ha abbandonato nel bosco scuro e sono riuscito a trovare la strada di casa tracciando le briciole all'indietro.

I breadcrumb in questo post non sono standard breadcrumb, sono simili ai breadcrumb. Offrono funzionalità aggiuntive inserendo pagine direttamente nella navigazione con un <select>, rendendo l'accesso a più livelli possibile.

UX in background

Nel video dimostrativo sui componenti riportato sopra, le categorie segnaposto sono generi di videogiochi. Questo sentiero viene creato seguendo il seguente percorso: home » rpg » indie » on sale, come mostrato di seguito.

Questo componente breadcrumb deve consentire agli utenti di spostarsi la gerarchia delle informazioni; saltando rami e selezionando pagine velocemente e la precisione.

Architettura dell'informazione

Penso che sia utile pensare in termini di raccolte ed elementi.

Raccolte

Una raccolta è un insieme di opzioni tra cui scegliere. Dalla home page di il prototipo di breadcrumb del post, le raccolte sono FPS, RPG, brawler, dungeon crawler, sport e rompicapi.

Elementi

Un videogioco è un elemento, anche una raccolta specifica potrebbe essere un elemento rappresenta un'altra raccolta. Ad esempio, RPG è un elemento e un modello . Se si tratta di un elemento, l'utente si trova nella pagina della raccolta. Ad esempio: nella pagina RPG, che mostra un elenco di giochi RPG, tra cui ulteriori sottocategorie "AAA", "Indie" e "Autopubblicati".

In termini informatici, questo componente dei breadcrumb rappresenta un multidimensionale di testo:

const rawBreadcrumbData = {
  "FPS": {...},
  "RPG": {
    "AAA": {...},
    "indie": {
      "new": {...},
      "on sale": {...},
      "under 5": {...},
    },
    "self published": {...},
  },
  "brawler": {...},
  "dungeon crawler": {...},
  "sports": {...},
  "puzzle": {...},
}

La tua app o il tuo sito web avranno un'architettura delle informazioni personalizzata (IA), creando un un array multidimensionale diverso, ma spero che il concetto di atterraggio della collezione pagine e l'attraversamento gerarchia possono comparire anche nei breadcrumb.

Layout

Aumento

I componenti efficaci iniziano con un codice HTML appropriato. Nella prossima sezione illustrerò scelte di markup e come influiscono sul componente complessivo.

Schema scuro e chiaro

<meta name="color-scheme" content="dark light">

Il meta tag color-scheme in alto Lo snippet comunica al browser che questa pagina richiede il browser chiaro e scuro. stili. I breadcrumb di esempio non includono CSS per queste combinazioni di colori, quindi i breadcrumb utilizzeranno i colori predefiniti forniti dal browser.

<nav class="breadcrumbs" role="navigation"></nav>

È opportuno utilizzare Elemento <nav> per la navigazione sul sito, che ha un ruolo ARIA implicito navigazione. Durante i test, ho notato che con l'attributo role il modo in cui un screen reader ha interagito con l'elemento, in realtà è stato annunciato di navigazione, quindi ho scelto di aggiungerla.

Icone

Quando un'icona si ripete su una pagina, il file SVG Elemento <use> significa che puoi definire path una volta e utilizzarlo per tutte le istanze . In questo modo le informazioni sul percorso non vengono ripetute, causando documenti più grandi e la potenziale incoerenza del percorso.

Per utilizzare questa tecnica, aggiungi un elemento SVG nascosto alla pagina e aggrega le icone in un elemento <symbol> con un ID univoco:

<svg style="display: none;">

  <symbol id="icon-home">
    <title>A home icon</title>
    <path d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"/>
  </symbol>

  <symbol id="icon-dropdown-arrow">
    <title>A down arrow</title>
    <path d="M19 9l-7 7-7-7"/>
  </symbol>

</svg>

Il browser legge l'HTML SVG, inserisce in memoria le informazioni sull'icona e continua con il resto della pagina facendo riferimento all'ID per ulteriori utilizzi dell'icona, in questo modo:

<svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true">
  <use href="#icon-home" />
</svg>

<svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true">
  <use href="#icon-dropdown-arrow" />
</svg>

DevTools che mostra un elemento di utilizzo SVG sottoposto a rendering.

Definite una volta e utilizzate tutte le volte che volete, con un impatto minimo sulle prestazioni della pagina. e stili flessibili. Nota che aria-hidden="true" viene aggiunto all'elemento SVG. Le icone non sono utili a chi naviga e ascolta solo i contenuti, nascondendo per impedire l'aggiunta di rumore superfluo.

È qui che divergono il breadcrumb tradizionale e quelli in questo componente. Normalmente, si tratta di un solo link <a>, ma ho aggiunto un'esperienza utente trasversale con un selezione camuffata. Il corso .crumb si occupa della disposizione del link e l'icona, mentre .crumbicon si occupa della sovrapposizione dell'icona e selezionare insieme. L'ho definito link divisi perché le sue funzioni sono molto simile a split-button, ma per la navigazione nelle pagine.

<span class="crumb">
  <a href="#sub-collection-b">Category B</a>
  <span class="crumbicon">
    <svg>...</svg>
    <select class="disguised-select" title="Navigate to another category">
      <option>Category A</option>
      <option selected>Category B</option>
      <option>Category C</option>
    </select>
  </span>
</span>

Un link e alcune opzioni non sono speciali, ma aggiungono più funzionalità a un breadcrumb semplice. L'aggiunta di title all'elemento <select> è utile per lo schermo agli utenti lettori, fornendo loro informazioni sull'azione del pulsante. Comunque offre lo stesso aiuto anche a tutti gli altri, vedrai che è in primo piano iPad. Un attributo fornisce il contesto del pulsante a molti utenti.

Screenshot in cui passi il mouse dell&#39;elemento invisibile select e i relativi
è visualizzata la descrizione comando contestuale.

Decorazioni separatore

<span class="crumb-separator" aria-hidden="true">→</span>

I separatori sono facoltativi; anche l'aggiunta di un solo separatore funziona molto bene (guarda il terzo esempio del video sopra). Poi do a ogni aria-hidden="true" perché sono decorativi e non qualcosa che uno screen reader deve annunciare.

La proprietà gap, trattata di seguito, semplifica la spaziatura di questi elementi.

Stili

Poiché il colore utilizza i colori del sistema, si tratta principalmente di spazi vuoti e impilati per gli stili.

Direzione e flusso del layout

DevTools che mostra l&#39;allineamento di navigazione dei breadcrumb con un overlay flexbox
funzionalità.

L'elemento di navigazione principale nav.breadcrumbs imposta una proprietà personalizzata con ambito che i bambini possono usare e stabilisce in altro modo una layout. In questo modo le briciole, i divisori e le icone saranno allineati.

.breadcrumbs {
  --nav-gap: 2ch;

  display: flex;
  align-items: center;
  gap: var(--nav-gap);
  padding: calc(var(--nav-gap) / 2);
}

Un breadcrumb mostrato verticalmente con gli overlay flexbox.

Ogni .crumb stabilisce anche un layout orizzontale allineato verticalmente con alcune gap, ma ha come target in modo speciale gli elementi secondari dei link e specifica lo stile white-space: nowrap. Questo è fondamentale per i breadcrumb di più parole, perché devono passare su più righe. Più avanti in questo post aggiungeremo gli stili per gestire overflow orizzontale di questa proprietà white-space causato.

.crumb {
  display: inline-flex;
  align-items: center;
  gap: calc(var(--nav-gap) / 4);

  & > a {
    white-space: nowrap;

    &[aria-current="page"] {
      font-weight: bold;
    }
  }
}

Il link aria-current="page" viene aggiunto per mettere in risalto il link della pagina corrente rispetto a e riposare. Non solo gli utenti di screen reader avranno un chiaro indicatore del fatto che il link sia per la pagina corrente, abbiamo applicato uno stile visivo all'elemento per aiutare gli utenti vedenti offrire un'esperienza utente simile.

Il componente .crumbicon utilizza una griglia per sovrapporre un'icona SVG all'icona "quasi invisibile" Elemento <select>.

DevTools a griglia mostrati sovrapposti a un pulsante in cui la riga e la colonna sono entrambe
stack denominato.

.crumbicon {
  --crumbicon-size: 3ch;

  display: grid;
  grid: [stack] var(--crumbicon-size) / [stack] var(--crumbicon-size);
  place-items: center;

  & > * {
    grid-area: stack;
  }
}

L'elemento <select> è l'ultimo nel DOM, quindi si trova in cima allo stack, e interattivo. Aggiungi lo stile opacity: .01 in modo che l'elemento sia ancora utilizzabile, il risultato è una casella di selezione che si adatta perfettamente alla forma dell'icona. Questo è un ottimo modo per personalizzare l'aspetto di un elemento <select>, mentre mantenendo la funzionalità integrata.

.disguised-select {
  inline-size: 100%;
  block-size: 100%;
  opacity: .01;
  font-size: min(100%, 16px); /* Defaults to 16px; fixes iOS zoom */
}

Overflow

I breadcrumb dovrebbero essere in grado di rappresentare una scia molto lunga. Adoro consentire fuori schermo in orizzontale, quando opportuno, e ho sentito dei breadcrumb correttamente.

.breadcrumbs {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scroll-padding-inline: calc(var(--nav-gap) / 2);

  & > .crumb:last-of-type {
    scroll-snap-align: end;
  }

  @supports (-webkit-hyphens:none) { & {
    scroll-snap-type: none;
  }}
}

Gli stili extra configurano la seguente UX:

  • Scorrimento orizzontale con contenimento overscroll.
  • Spaziatura interna di scorrimento orizzontale.
  • Un punto di scatto sull'ultima briciola. Ciò significa che al caricamento della pagina carichi di briciole agganciati e visibili.
  • Rimuove il punto di aggancio da Safari, che ha difficoltà con l'orientamento orizzontale combinazioni di effetti di scorrimento e aggancio.

Query supporti

Una piccola modifica alle aree visibili più piccole è nascondere "Home" etichetta, lasciando solo l'icona:

@media (width <= 480px) {
  .breadcrumbs .home-label {
    display: none;
  }
}

Affiancato ai breadcrumb con e senza etichetta Home, ad esempio
a confronto.

Accessibilità

Movimento

Non c'è molto movimento in questo componente, ma racchiudendo la transizione in un controllo prefers-reduced-motion, possiamo impedire movimenti indesiderati.

@media (prefers-reduced-motion: no-preference) {
  .crumbicon {
    transition: box-shadow .2s ease;
  }
}

Nessuno degli altri stili deve cambiare, gli effetti al passaggio del mouse e di messa a fuoco sono fantastici e significativo senza transition, ma se il movimento è accettabile, aggiungeremo un transizione all'interazione.

JavaScript

Innanzitutto, a prescindere dal tipo di router utilizzato nel sito o nell'applicazione, Quando un utente modifica i breadcrumb, l'URL deve essere aggiornato e l'utente visualizzata la pagina appropriata. In secondo luogo, per normalizzare l'esperienza utente, non si verificano navigazioni impreviste quando gli utenti navigano su <select> le opzioni di CPU e memoria disponibili.

Due misure fondamentali per l'esperienza utente che devono essere gestite da JavaScript: select ha prevenzione dell'attivazione di eventi di modifica <select> modificata e desiderosa.

È necessaria la prevenzione di eventi "eager" grazie all'uso di un <select> . Su Windows Edge e probabilmente anche in altri browser, changed si attiva mentre l'utente sfoglia le opzioni con la tastiera. È per questo che chiamato "eager", dato che l'utente ha solo pseudo selezionato l'opzione, come o focus, ma non ha ancora confermato la scelta con enter o click. L'impazienza rende inaccessibile la funzione di modifica della categoria del componente, perché aprire la casella di selezione e semplicemente sfogliare un elemento attiverà l'evento e modificare la pagina prima che l'utente sia pronto.

Un evento <select> migliore modificato

const crumbs = document.querySelectorAll('.breadcrumbs select')
const allowedKeys = new Set(['Tab', 'Enter', ' '])
const preventedKeys = new Set(['ArrowUp', 'ArrowDown'])

// watch crumbs for changes,
// ensures it's a full value change, not a user exploring options via keyboard
crumbs.forEach(nav => {
  let ignoreChange = false

  nav.addEventListener('change', e => {
    if (ignoreChange) return
    // it's actually changed!
  })

  nav.addEventListener('keydown', ({ key }) => {
    if (preventedKeys.has(key))
      ignoreChange = true
    else if (allowedKeys.has(key))
      ignoreChange = false
  })
})

La strategia per farlo è controllare gli eventi Tastiera giù ogni <select> e stabilire se il tasto premuto è la conferma della navigazione (Tab o Enter) o navigazione spaziale (ArrowUp o ArrowDown). Con questo determinante, il componente può decidere di attendere o di andare, quando l'evento per Viene attivato <select> elemento.

Conclusione

Ora che sai come ci ho fatto, come faresti‽ 🙂

Diversificaamo i nostri approcci e impariamo tutti i modi per creare sul web. Crea una demo, twittami con i link e la aggiungerò alla sezione dei remix della community qui sotto.

Remix della community