Breadcrumbs-Komponente erstellen

Eine grundlegende Übersicht darüber, wie Sie eine responsive und barrierefreie Breadcrumb-Komponente erstellen, mit der Nutzer auf Ihrer Website navigieren können.

In diesem Beitrag möchte ich zeigen, wie man Breadcrumb-Komponenten erstellt. Demo ansehen.

Demo

Falls du lieber ein Video hast, findest du hier eine YouTube-Version dieses Beitrags:

Überblick

Eine Navigationspfad-Komponente zeigt an, wo in der Websitehierarchie sich der Nutzer befindet. Der Name stammt von Hänsel und Gretel, die einen Navigationspfad in einigen dunklen Wäldern hinter ihnen abgelegt haben und den Weg nach Hause finden, indem sie die Brotkrümel rückwärts verfolgen.

Die Navigationspfade in diesem Beitrag sind keine Standard-Navigationspfade, sondern ähneln denen. Sie bieten zusätzliche Funktionen, da gleichgeordnete Seiten mit einem <select> direkt in die Navigation eingefügt werden, was einen mehrstufigen Zugriff ermöglicht.

Hintergrund-UX

Im Demovideo zu Komponenten oben sind die Platzhalterkategorien Genres von Videospielen. Dieser Pfad wird über den folgenden Pfad erstellt: home » rpg » indie » on sale (siehe unten).

Diese Breadcrumb-Komponente soll es Nutzern ermöglichen, sich durch diese Informationshierarchie zu bewegen, Zweige zu wechseln und Seiten schnell und präzise auszuwählen.

Informationsarchitektur

Ich finde es hilfreich, in Sammlungen und Gegenständen zu denken.

Sammlungen

Eine Sammlung besteht aus einer Reihe von Optionen. Auf der Startseite des Navigationspfad-Prototyps dieses Beitrags findest du die Sammlungen „FPS“, „Rollenspiel“, „Bawler“, „Dungeon-Crawler“, „Sport“ und „Puzzle“.

Elemente

Ein Videospiel ist ein Objekt. Eine bestimmte Sammlung kann auch ein Objekt sein, wenn es eine andere Sammlung repräsentiert. Ein Rollenspiel ist beispielsweise ein Element und eine gültige Sammlung. Wenn es ein Element ist, befindet sich der Nutzer auf der entsprechenden Sammlungsseite. Sie befinden sich beispielsweise auf der Seite „Rollenspiele“ mit einer Liste von Rollenspielen, einschließlich der zusätzlichen Unterkategorien „AAA“, „Indie“ und „Selbst veröffentlicht“.

In der Informatik stellt diese Klickpfadkomponente ein mehrdimensionales Array dar:

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

Ihre App oder Website wird eine benutzerdefinierte Informationsarchitektur (IA) haben, die ein anderes mehrdimensionales Array erstellt. Ich hoffe aber, dass das Konzept der Sammlungs-Landingpages und der Hierarchiedurchlauf auch in Ihre Navigationspfade einfließen können.

Layouts

Markup

Gute Komponenten beginnen mit passendem HTML. Im nächsten Abschnitt erkläre ich meine Markup-Optionen und wie sie sich auf die Komponente insgesamt auswirken.

Dunkles und helles Schema

<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 das helle und das dunkle Browserdesign verwendet werden soll. Die Beispiel-Breadcrumbs enthalten kein CSS für diese Farbschemata, sodass darin die vom Browser bereitgestellten Standardfarben verwendet werden.

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

Für die Websitenavigation sollte das Element <nav> verwendet werden, da es 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 verändert hat und dass es eigentlich als Navigation angekündigt wurde. Deshalb habe ich mich dazu entschlossen, es hinzuzufügen.

Symbole

Wenn ein Symbol auf einer Seite wiederholt wird, können Sie mit dem SVG-Element <use> path einmal definieren und dann für alle Instanzen des Symbols verwenden. Dadurch wird verhindert, dass dieselben Pfadinformationen wiederholt werden, was zu größeren Dokumenten und potenziell inkonsistenten Pfaden führt.

Für dieses Verfahren fügen Sie der Seite ein ausgeblendetes SVG-Element hinzu und binden 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 den SVG-HTML-Code, speichert die Symbolinformationen im Speicher und fährt mit dem Rest der Seite fort, um auf die ID für weitere Verwendungen des Symbols zu verweisen:

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

Entwicklertools mit einem gerenderten SVG-Use-Element.

Einmal definieren und beliebig oft verwenden – mit minimaler Auswirkung auf die Seitenleistung und flexiblen Stilen. Beachten Sie, dass aria-hidden="true" dem SVG-Element hinzugefügt wurde. Die Symbole sind für Nutzer, die nur den Inhalt hören, nicht hilfreich. Wenn sie vor den Nutzern ausgeblendet werden, wird unnötiges Rauschen verhindert.

Hier weichen der traditionelle Navigationspfad von denen in dieser Komponente ab. Normalerweise wäre dies nur ein <a>-Link, aber ich habe Durchlauf-UX mit einer getarnten Auswahl hinzugefügt. Die .crumb-Klasse ist für das Layout von Link und Symbol verantwortlich, während .crumbicon für das Stapeln des Symbols und des ausgewählten Elements verantwortlich ist. Ich habe diesen Link als Split-Link bezeichnet, weil seine Funktionen einer Split-Schaltfläche sehr ähnlich sind, 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, sondern ergänzen einen einfachen Navigationspfad um mehr Funktionen. Das Hinzufügen eines title zum <select>-Element ist für Nutzer von Screenreadern hilfreich, da sie ihnen Informationen über die Aktion der Schaltfläche geben. Es bietet jedoch auch allen anderen dieselbe Hilfe, Sie werden auf dem iPad feststellen, dass es zentral verfügbar ist. Ein Attribut stellt vielen Nutzern Schaltflächenkontext zur Verfügung.

Screenshot mit dem eingeblendeten unsichtbaren select-Element und seiner kontextabhängigen Kurzinfo.

Trennzeichen

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

Trennzeichen sind optional. Auch das Hinzufügen eines Trennzeichens funktioniert sehr gut (siehe drittes Beispiel im Video oben). Dann gebe ich jedem aria-hidden="true", da sie dekorativ sind und nichts mitteilen müssen, das ein Screenreader vorlesen muss.

Die gap-Eigenschaft, die als Nächstes beschrieben wird, vereinfacht die Abstände zwischen den beiden.

Stile

Da für die Farbe Systemfarben verwendet werden, handelt es sich hauptsächlich um Lücken und Stacks für Stile.

Layoutrichtung und -fluss

Entwicklertools, die die Navigationspfadausrichtung mit einer zugehörigen Flexbox-Overlay-Funktion zeigen.

Das primäre Navigationselement nav.breadcrumbs legt eine bereichsspezifische benutzerdefinierte Eigenschaft fest, die von Kindern verwendet werden kann. Darüber hinaus wird ein horizontal vertikal ausgerichtetes Layout erstellt. Dadurch wird sichergestellt, dass die Navigationspfade, Trennlinien und Symbole aufeinander abgestimmt sind.

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

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

Ein Navigationspfad, der vertikal an den Flexbox-Overlays ausgerichtet ist.

Jedes .crumb-Element erstellt auch ein horizontal vertikal ausgerichtetes Layout mit einer gewissen Lücke, zielt aber speziell auf die untergeordneten Link-Elemente ab und gibt den Stil white-space: nowrap an. Dies ist für Navigationspfade mit mehreren Wörtern sehr wichtig, da sie nicht mehrzeilig werden sollen. Später in diesem Beitrag werden wir Stile hinzufügen, um den horizontalen Überlauf zu bewältigen, den diese white-space-Eigenschaft verursacht hat.

.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 aktuelle Seitenlink von der Masse abhebt. Nutzer von Screenreadern erkennen nicht nur, dass sich der Link auf die aktuelle Seite bezieht, wir haben das Element auch optisch gestaltet, um sehenden Nutzern eine ähnliche Nutzererfahrung zu ermöglichen.

Die Komponente .crumbicon verwendet ein Raster, um ein SVG-Symbol mit einem fast unsichtbaren <select>-Element zu stapeln.

Grid DevTools überlagert eine Schaltfläche, wobei sowohl die Zeile als auch die Spalte einen benannten Stack haben.

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

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

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

Das <select>-Element befindet sich an letzter Stelle im DOM. Es befindet sich also oberhalb des Stacks 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 lässt sich das Aussehen eines <select>-Elements bei gleichbleibender integrierter Funktionalität anpassen.

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

Überlauf

Navigationspfade sollten einen sehr langen Weg darstellen können. Ich finde es großartig, dass sich Elemente gegebenenfalls horizontal aus dem Bildschirm bewegen lassen, und habe den Eindruck, dass sich diese Komponente gut eignet.

.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 Überlaufstile wird die folgende UX eingerichtet:

  • Horizontales Scrollen mit Overscroll-Begrenzung.
  • Horizontaler Abstand zum Scrollen.
  • Ein Klickpunkt auf der letzten Krümel. Das bedeutet, dass beim Seitenaufbau der erste Schritt im Bild ist und angedockt wird.
  • Dadurch wird der Snap Point aus Safari entfernt, der Probleme mit horizontalen Scroll- und Snap-Effekt-Kombinationen hat.

Medienabfragen

Eine subtile Anpassung für kleinere Darstellungsbereiche besteht darin, das Label „Startseite“ auszublenden, sodass nur das Symbol übrig bleibt:

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

Zum Vergleich Seite an Seite der Navigationspfade mit und ohne Home-Label.

Barrierefreiheit

Bewegung

Diese Komponente enthält nicht viel Bewegung, aber durch die Einbindung des Übergangs in eine prefers-reduced-motion-Prüfung können unerwünschte Bewegungen verhindert werden.

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

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

JavaScript

Unabhängig vom Typ des Routers, den Sie auf Ihrer Website oder in Ihrer Anwendung verwenden, muss die URL aktualisiert werden, wenn ein Nutzer den Navigationspfad ändert und ihm die entsprechende Seite angezeigt wird. Zweitens: Sorgen Sie für eine normale Nutzerfreundlichkeit dafür, dass keine unerwarteten Navigationen auftreten, wenn Nutzer nur <select>-Optionen ansehen.

Zwei wichtige Maßnahmen für die Nutzerfreundlichkeit, die von JavaScript verarbeitet werden müssen: Die Auswahl hat sich geändert und die Auslösung von <select>-Änderungsereignissen kann aktiv verhindert werden.

Die eager-Ereignisverhinderung ist aufgrund der Verwendung eines <select>-Elements erforderlich. Unter Windows Edge und wahrscheinlich auch in anderen Browsern wird das changed-Ereignis ausgelöst, wenn der Nutzer Optionen mit der Tastatur durchsucht. Aus diesem Grund habe ich die Option „eager“ genannt, da der Nutzer die Option nur pseudobasiert ausgewählt hat, z. B. Mauszeiger oder Fokus, aber die Auswahl noch nicht mit enter oder click bestätigt hat. Durch das eager-Ereignis ist die Funktion zum Ändern der Komponentenkategorie nicht mehr zugänglich, da beim Öffnen des Auswahlfelds und beim einfachen Suchen eines Elements das Ereignis ausgelöst und die Seite geändert wird, bevor der Nutzer bereit ist.

Besserer geänderter Termin (<select>)

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

Beobachten Sie hierzu bei jedem <select>-Element, ob die gedrückte Taste auf der Tastatur gedrückt wurde, und um zu ermitteln, ob es sich bei der gedrückten Taste um die Navigationsbestätigung (Tab oder Enter) oder die räumliche Navigation (ArrowUp oder ArrowDown) handelt.<select>

Fazit

Jetzt weißt du, wie ich es gemacht habe. Wie würdest du es erreichen? 🙂

Diversifizieren wir unsere Ansätze und lernen Sie alle Möglichkeiten kennen, wie wir das Web nutzen können. Erstelle eine Demo und twittere mich über Links, und ich füge sie unten zum Abschnitt über Community-Remixe hinzu.

Community-Remixe