Breadcrumbs-Komponente erstellen

Ein grundlegender Überblick über die Erstellung einer responsiven und zugänglichen Navigationspfadkomponente, mit der Nutzer auf Ihrer Website navigieren können.

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:

Überblick

Eine Navigationspfadkomponente zeigt an, wo sich der Nutzer in der Websitehierarchie befindet. Der Name stammt von Hänsel und Gretel, die in dunklem Wald Breadcrumbs hinter ihnen platziert haben und durch Rückwärtsbewegungen den Weg nach Hause finden konnten.

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

Hintergrund: UX

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

Diese Navigationspfadkomponente sollte es Nutzern ermöglichen, sich durch diese Informationshierarchie zu bewegen, Zweige zu springen und Seiten schnell und genau auszuwählen.

Informationsarchitektur

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

Kollektionen

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

Elemente

Bei einem Videospiel handelt es sich um einen Artikel. Eine bestimmte Sammlung könnte auch ein Artikel sein, wenn sie eine andere Sammlung repräsentiert. Ein Rollenspiel ist beispielsweise ein Gegenstand und eine gültige Sammlung. Wenn es sich um ein Element handelt, befindet sich der Nutzer auf dieser Sammlungsseite. Sie befinden sich beispielsweise auf der Rollenspiel-Seite, die eine Liste von Rollenspielen mit den zusätzlichen Unterkategorien AAA, Indie und selbst veröffentlicht enthält.

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 verfügt über eine benutzerdefinierte Informationsarchitektur (IA), die ein anderes mehrdimensionales Array erzeugt. Ich hoffe aber, dass das Konzept der Sammlungs-Landingpages und der Hierarchiedurchlauf auch in Ihren Navigationspfaden umgesetzt werden können.

Layouts

Markup

Gute Komponenten beginnen mit geeignetem HTML. Im nächsten Abschnitt geht es um meine Markup-Optionen und deren Auswirkungen auf die Gesamtkomponente.

Dunkles und helles Design

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

Das Meta-Tag color-scheme im obigen Snippet informiert den Browser darüber, dass diese Seite den hellen und den dunklen Browserstil verwenden möchte. 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. Beim Testen habe ich festgestellt, dass sich durch das Attribut role die Art und Weise ändert, wie ein Screenreader mit dem Element interagiert. Tatsächlich wurde es als Navigation angekündigt, daher habe ich es hinzugefügt.

Symbole

Wenn sich ein Symbol auf einer Seite wiederholt, kannst du path mithilfe des SVG-Elements <use> einmal definieren und für alle Instanzen des Symbols verwenden. Dies verhindert, dass dieselben Pfadinformationen wiederholt werden, was zu größeren Dokumenten und möglicherweise zu Pfadinkonsistenzen führt.

Wenn Sie diese Technik verwenden möchten, fügen Sie der Seite ein ausgeblendetes SVG-Element hinzu und umschließen Sie die Symbole in einem <symbol>-Element mit einer eindeutigen ID:

<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, speichert die Symbolinformationen in den Arbeitsspeicher und fährt mit dem Rest der Seite fort, der auf die ID verweist, um das Symbol weiter zu verwenden:

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

Definieren Sie die Methode einmal und verwenden Sie sie beliebig oft mit minimalen Auswirkungen auf die Seitenleistung und flexible Gestaltung. Beachten Sie, dass dem SVG-Element aria-hidden="true" hinzugefügt wurde. Die Symbole sind für Nutzer, die nur den Inhalt hören, nicht nützlich. Wenn sie sie vor den Nutzern verbergen, fügen sie kein unnötiges Rauschen hinzu.

Hier weichen der herkömmliche Navigationspfad von denen in dieser Komponente ab. Normalerweise wäre das 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 es Split-Link genannt, weil seine Funktionen der Split-Schaltfläche sehr ähnlich sind, jedoch 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 fügen einem einfachen Navigationspfad zusätzliche Funktionen hinzu. 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 stellt vielen Nutzenden den Schaltflächenkontext bereit.

Screenshot mit dem unsichtbaren select-Element, auf das der Mauszeiger bewegt wird, und dessen kontextueller Kurzinfo angezeigt wird

Separator-Dekorationen

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

Trennzeichen sind optional. Es reicht auch aus, nur eines hinzuzufügen (siehe drittes Beispiel im Video oben). Anschließend gebe ich jede aria-hidden="true", da sie dekorativ sind und nichts, was ein Screenreader sagen muss.

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

Stile

Da für die Farbe Systemfarben verwendet werden, handelt es sich bei Stilen meistens um Lücken und Stapel.

Layoutrichtung und -fluss

Entwicklertools, die die Ausrichtung des Navigationspfads mit einer Flexbox-Overlay-Funktion zeigen.

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. Dadurch wird sichergestellt, dass die Brüche, Trennlinien und Symbole aufeinander ausgerichtet sind.

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

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

Ein Navigationspfad, der vertikal mit Flexbox-Overlays ausgerichtet ist.

Jede .crumb stellt auch ein horizontal vertikal ausgerichtetes Layout mit einer Lücke dar, richtet aber speziell auf die untergeordneten Linkelemente aus und gibt den Stil white-space: nowrap an. Dies ist wichtig für Navigationspfade, die aus mehreren Wörtern bestehen, da sie nicht mehrzeilig sein sollen. Später in diesem Beitrag werden wir Stile hinzufügen, um den durch diese white-space-Eigenschaft verursachten horizontalen Überlauf zu verarbeiten.

.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 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 benannt 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, und erhalten Sie ein Auswahlfeld, das perfekt zur Form des Symbols passt. So können Sie das Aussehen eines <select>-Elements anpassen und gleichzeitig die integrierte Funktionalität beibehalten.

.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. Ich liebe es, Dinge horizontal zu erlauben, wenn es angebracht ist, und fand diese Breadcrumb-Komponente gut geeignet.

.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 Abstand beim Scrollen.
  • Ein Andockpunkt auf dem letzten Navigationspfad. Das bedeutet, dass beim Laden der Seite der erste Brotkrumen angedockt und sichtbar ist.
  • Der Andockpunkt wird aus Safari entfernt, was mit den Kombinationen aus horizontalem Scrollen und Andocken-Effekt zu kämpfen 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 nebeneinander die Navigationspfade 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 Mouseover- und Fokuseffekte sind auch ohne transition hervorragend und aussagekräftig. Wenn Bewegung jedoch 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 sollten Sie zur Normalisierung der Nutzerfreundlichkeit darauf achten, dass keine unerwarteten Navigationen erfolgen, wenn Nutzer nur <select>-Optionen durchstöbern.

Zwei wichtige Maßnahmen für die Nutzererfahrung, die von JavaScript verarbeitet werden müssen: „Select hat sich geändert“ und der Schutz vor <select>-Änderungsereignissen soll verhindert werden.

Aufgrund der Verwendung eines <select>-Elements ist die effektive Ereignisverhinderung erforderlich. In Windows Edge und wahrscheinlich auch in anderen Browsern wird das Ereignis changed ausgelöst, wenn der Nutzer über die Tastatur nach Optionen navigiert. Deshalb habe ich die Funktion „eager“ genannt, da der Nutzer die Option nur per Pseudo ausgewählt hat, z. B. über einen Mauszeiger oder einen Fokus, aber die Auswahl mit enter oder click noch nicht bestätigt hat. Durch das „eager“-Ereignis wird diese Funktion zum Ändern der Komponentenkategorie nicht zugänglich, da das Ereignis ausgelöst und die Seite geändert wird, bevor der Nutzer bereit ist, wenn Sie das Auswahlfeld öffnen und einfach nach einem Element suchen.

Ein besserer geänderter Termin für <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
  })
})

Die Strategie besteht darin, bei jedem <select>-Element auf Keyboard-Down-Ereignisse zu achten und zu ermitteln, ob die gedrückte Taste die Navigationsbestätigung (Tab oder Enter) oder die räumliche Navigation (ArrowUp oder ArrowDown) war. Die Komponente kann dann entscheiden, ob sie warten oder gehen soll, wenn das Ereignis für das <select>-Element ausgelöst wird.

Fazit

Jetzt, wo du weißt, wie ich es gemacht habe, wie würdest du... ‽ 🙂

Lassen Sie uns unsere Herangehensweisen diversifizieren und alle Möglichkeiten kennenlernen, wie wir das Web entwickeln können. Erstelle eine Demo, Tweets an mich und füge sie unten im Abschnitt zu Community-Remixen hinzu.

Community-Remixe