Breadcrumbs-Komponente erstellen

Eine grundlegende Übersicht dazu, wie Sie eine responsive und barrierefreie Navigationsstruktur für Nutzer erstellen, die die Navigation auf Ihrer Website vereinfacht.

In diesem Beitrag möchte ich Ihnen zeigen, wie Sie Navigationspfade erstellen können. Demo ansehen.

Demo

Falls Sie Videos bevorzugen, finden Sie hier eine YouTube-Version dieses Beitrags:

Übersicht

Eine Brotkrummen-Komponente zeigt an, wo sich der Nutzer in der Websitehierarchie befindet. Der Name stammt aus dem Märchen Hänsel und Gretel, in dem die beiden in einem dunklen Wald Brotkrumen hinter sich warfen und so den Weg nach Hause zurückverfolgen konnten.

Die Breadcrumbs in diesem Beitrag sind keine Standard-Breadcrumbs, sondern nur ähnlich. Sie bieten zusätzliche Funktionen, da über ein <select> die Navigationsleiste direkt in die Navigationsleiste eingefügt wird, was einen mehrstufigen Zugriff ermöglicht.

UX-Hintergrund

Im Demovideo für Komponenten oben sind die Platzhalterkategorien die Genres von Videospielen. Dieser Pfad wird wie unten dargestellt über den Pfad home » rpg » indie » on sale erstellt.

Mit dieser Breadcrumb-Komponente sollten Nutzer in der Lage sein, sich durch diese Informationshierarchie zu bewegen, Äste zu überspringen und Seiten schnell und genau auszuwählen.

Informationsarchitektur

Ich finde es hilfreich, in Bezug auf Sammlungen und Objekte zu denken.

Sammlungen

Eine Sammlung besteht aus einer Reihe von Optionen, aus denen Sie auswählen können. Von der Startseite des Navigationspfad-Prototyps dieses Beitrags aus sind die Sammlungen Ego-Shooter, Rollenspiel, Prügelspiel, Dungeon-Crawler, Sport und Puzzle.

Elemente

Ein Videospiel ist ein Artikel. Eine bestimmte Sammlung kann auch ein Artikel sein, wenn sie eine andere Sammlung darstellt. „RPG“ ist beispielsweise ein Element und eine gültige Sammlung. Wenn es sich um ein Element handelt, befindet sich der Nutzer auf der Sammlungsseite. Sie finden sie beispielsweise auf der Seite „Rollenspiele“, auf der eine Liste von Rollenspielen mit den zusätzlichen Unterkategorien „AAA“, „Indie“ und „Selbst veröffentlicht“ angezeigt wird.

In der Informatik stellt diese Navigationspfadkomponente ein multidimensionales Array dar:

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

Ihre App oder Website hat eine benutzerdefinierte Informationsarchitektur (IA), die ein anderes mehrdimensionales Array erstellt. Ich hoffe aber, dass das Konzept der Landingpages für Sammlungen und die Hierarchieaufschlüsselung auch in Ihre Breadcrumbs einfließen kann.

Layouts

Markup

Gute Komponenten beginnen mit dem richtigen HTML-Code. Im nächsten Abschnitt erkläre ich meine Markierungsentscheidungen und wie sie sich auf die gesamte Komponente auswirken.

Dunkles und helles Farbschema

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

Das Meta-Tag color-scheme im obigen Snippet informiert den Browser darüber, dass für diese Seite der helle und der dunkle Browserstil verwendet werden sollen. Die Beispiel-Navigationspfade enthalten kein CSS für diese Farbschemata. Für sie werden also die vom Browser bereitgestellten Standardfarben verwendet.

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

Für die Websitenavigation empfiehlt es sich, das Element <nav> zu verwenden, das eine implizite ARIA-Rolle für die Navigation hat. Bei den Tests habe ich festgestellt, dass sich durch das role-Attribut die Interaktion eines Screenreaders mit dem Element geändert hat. Es wurde tatsächlich als Navigation angekündigt. Deshalb habe ich es hinzugefügt.

Symbole

Wenn ein Symbol auf einer Seite wiederholt wird, können Sie mit dem SVG-Element <use> das path einmal definieren und für alle Instanzen des Symbols verwenden. So wird verhindert, dass sich dieselben Pfadinformationen wiederholen, was zu größeren Dokumenten und möglicherweise zu Pfadinkonsistenzen führt.

Fügen Sie dazu der Seite ein ausgeblendetes SVG-Element hinzu und fügen Sie die Symbole in ein <symbol>-Element mit einer eindeutigen ID ein:

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

Der Browser liest die SVG-HTML-Daten, speichert die Symbolinformationen im Arbeitsspeicher und fährt mit dem Rest der Seite fort, wobei auf die ID für weitere Verwendungen des Symbols verwiesen wird, z. B. so:

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

In den DevTools wird ein gerendertes SVG-Element angezeigt.

Einmal definieren, beliebig oft verwenden, mit minimalen Auswirkungen auf die Seitenleistung und flexiblem Styling. Beachten Sie, dass dem SVG-Element aria-hidden="true" hinzugefügt wird. Die Symbole sind für Nutzer, die sich Inhalte nur anhören, nicht nützlich. Wenn sie ausgeblendet werden, können sie nicht als unnötiger Störfaktor dienen.

Hier weichen die traditionellen Breadcrumbs von denen in dieser Komponente ab. Normalerweise wäre dies nur ein <a>-Link, aber ich habe die Durchlauf-UX mit einer getarnten Auswahl hinzugefügt. Die Klasse .crumb ist für das Layout des Links und des Symbols verantwortlich, während die Klasse .crumbicon für das Stapeln des Symbols und der Auswahlelemente zuständig ist. Ich habe ihn als Split-Link bezeichnet, weil seine Funktionen denen einer Split-Schaltfläche ähneln, aber für die Seitennavigation.

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

Ein Link und einige Optionen sind nichts Besonderes, verleihen einer einfachen Navigationsleiste aber mehr Funktionalität. Das Hinzufügen eines title zum <select>-Element ist für Nutzer von Screenreadern hilfreich, da sie Informationen zur Aktion der Schaltfläche erhalten. Es bietet jedoch auch allen anderen dieselbe Hilfe, Sie werden auf dem iPad sehen, dass sie in der Mitte liegt. Ein Attribut liefert den Schaltflächenkontext für viele Nutzer.

Screenshot, in dem der Mauszeiger auf das unsichtbare Auswahlelement bewegt wird und die kontextbezogene Kurzinfo angezeigt wird

Trennzeichendekorationen

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

Trennzeichen sind optional. Es reicht auch, nur eins hinzuzufügen (siehe drittes Beispiel im Video oben). Ich gebe dann jedem aria-hidden="true" einen, da sie dekorativ sind und nicht etwas, das ein Screenreader ansagen muss.

Die Eigenschaft gap, die im Folgenden beschrieben wird, vereinfacht die Abstände dieser Elemente.

Stile

Da für die Farbe Systemfarben verwendet werden, sind es hauptsächlich Lücken und Stapel für Stile.

Layoutrichtung und -fluss

In den DevTools wird die Ausrichtung des Navigationspfads mithilfe der Flexbox-Overlay-Funktion angezeigt.

Mit dem primären Navigationselement nav.breadcrumbs wird eine benutzerdefinierte, auf einen Bereich reduzierte Eigenschaft festgelegt, die Kinder verwenden können. Außerdem wird damit ein horizontal vertikal ausgerichtetes Layout festgelegt. So sorgen Sie dafür, dass die Breadcrumbs, Trennlinien und Symbole ausgerichtet sind.

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

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

Ein Breadcrumb-Trail, der vertikal mit Flexbox-Overlays ausgerichtet ist.

Jedes .crumb legt auch ein horizontales, vertikal ausgerichtetes Layout mit etwas Abstand fest, richtet sich aber speziell auf seine Link-Untergeordneten aus und gibt den Stil white-space: nowrap an. Dies ist entscheidend für Breadcrumbs mit mehreren Wörtern, da sie nicht mehrzeilig sein sollen. Später in diesem Artikel fügen wir Stile hinzu, um den horizontalen Überlauf zu verwalten, der durch diese white-space-Eigenschaft verursacht wurde.

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

  & > a {
    white-space: nowrap;

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

aria-current="page" wird hinzugefügt, damit sich der Link zur aktuellen Seite von den anderen abhebt. Screenreader-Nutzer können nicht nur deutlich erkennen, dass sich der Link auf die aktuelle Seite bezieht, sondern auch das Element optisch gestaltet, um sehenden Nutzern eine ähnliche Nutzererfahrung zu bieten.

In der Komponente .crumbicon wird ein Raster verwendet, um ein SVG-Symbol mit einem „nahezu unsichtbaren“ <select>-Element zu stapeln.

Grid-Entwicklertools werden über einer Schaltfläche angezeigt, wobei Zeile und Spalte beide als „Stack“ bezeichnet sind.

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

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

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

Das <select>-Element steht im DOM an letzter Stelle, also befindet es sich auf dem Stack und ist interaktiv. Fügen Sie den Stil opacity: .01 hinzu, damit das Element weiterhin verwendet werden kann. Das Ergebnis ist ein Auswahlfeld, das perfekt zur Form des Symbols passt. So können Sie das Aussehen eines <select>-Elements anpassen und gleichzeitig die integrierten Funktionen beibehalten.

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

Überlauf

Breadcrumbs sollten einen sehr langen Pfad darstellen können. Ich bin ein Fan davon, Elemente bei Bedarf horizontal außerhalb des Bildschirms zu platzieren. Ich fand, dass diese Breadcrumb-Komponente gut geeignet war.

.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;
  }}
}

Mit den Überlauf-Stilen wird die folgende UX eingerichtet:

  • Horizontales Scrollen mit Overscroll-Begrenzung
  • Horizontaler Bildlauf-Abstand
  • Ein Snap-Punkt am letzten Stützpunkt. Das bedeutet, dass beim Laden der Seite der erste Breadcrumb an der richtigen Stelle und im Blickfeld geladen wird.
  • Der Anknüpfungspunkt wird aus Safari entfernt, da es Probleme mit der Kombination aus horizontalem Scrollen und Anknüpfungseffekten gab.

Medienabfragen

Eine subtile Anpassung für kleinere Ansichten besteht darin, das Label „Startseite“ auszublenden und nur das Symbol zu behalten:

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

Direkter Vergleich der Breadcrumbs mit und ohne Startseitenlabel

Bedienungshilfen

Bewegung

In dieser Komponente gibt es nicht viele Bewegungen, aber wenn wir den Übergang in eine prefers-reduced-motion-Prüfung einschließen, können wir unerwünschte Bewegungen verhindern.

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

Keiner der anderen Stile muss geändert werden. Die Hover- und Fokuseffekte sind auch ohne transition gut und aussagekräftig. Wenn Bewegung in Ordnung ist, fügen wir der Interaktion einen subtilen Übergang hinzu.

JavaScript

Unabhängig vom Routertyp, den Sie auf Ihrer Website oder in Ihrer Anwendung verwenden, muss die URL aktualisiert und der Nutzer die entsprechende Seite angezeigt werden, wenn ein Nutzer den Navigationspfad ändert. Zweitens: Sorgen Sie dafür, dass Nutzer nicht unerwartet weitergeleitet werden, wenn sie sich nur die <select>-Optionen ansehen.

Zwei wichtige Maßnahmen zur Nutzerfreundlichkeit, die von JavaScript verarbeitet werden müssen: „select has changed“ und die Vermeidung des vorzeitigen Auslösens von <select>-Änderungsereignissen.

Die frühzeitige Ereignisprävention ist aufgrund der Verwendung eines <select>-Elements erforderlich. In Windows Edge und wahrscheinlich auch in anderen Browsern wird das Ereignis „select“ changed ausgelöst, wenn der Nutzer mit der Tastatur Optionen durchsucht. Deshalb habe ich es „vorschnell“ genannt, da der Nutzer die Option nur vorgeblich ausgewählt hat, z. B. durch Bewegen des Mauszeigers oder durch Fokussieren, die Auswahl aber nicht mit enter oder click bestätigt hat. Durch das vorzeitige Ereignis ist diese Funktion zur Änderung der Komponentenkategorie nicht zugänglich, da das Ereignis ausgelöst und die Seite geändert wird, sobald das Auswahlfeld geöffnet und ein Artikel aufgerufen wird, bevor der Nutzer bereit ist.

Verbessertes Ereignis „<select> geändert“

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

Dazu wird bei jedem <select>-Element auf ein Tastendruckereignis geachtet und ermittelt, ob die gedrückte Taste eine Navigationsbestätigung (Tab oder Enter) oder eine räumliche Navigation (ArrowUp oder ArrowDown) war. Anhand dieser Bestimmung kann die Komponente entscheiden, ob sie warten oder fortfahren soll, wenn das Ereignis für das <select>-Element ausgelöst wird.

Fazit

Wie würden Sie das machen?

Lassen Sie uns unsere Ansätze diversifizieren und alle Möglichkeiten kennenlernen, wie Sie im Web entwickeln können. Erstelle eine Demo, tweete mir Links und ich füge sie unten in den Abschnitt „Community-Remixe“ hinzu.

Remixe der Community