Komponente „Sidenav“ erstellen

Grundlegende Übersicht zum Erstellen einer responsiven Slide-Out-Side-Navigation

In diesem Beitrag möchte ich Ihnen zeigen, wie ich einen Prototyp einer Sidenav-Komponente für das Web entwickelt habe, die responsiv, zustandsorientiert ist, die Tastaturnavigation unterstützt, mit und ohne JavaScript funktioniert und browserübergreifend funktioniert. Demo ansehen

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

Überblick

Es ist nicht einfach, ein reaktionsschnelles Navigationssystem zu entwickeln. Einige Nutzer arbeiten mit einer Tastatur, andere haben einen leistungsstarken Desktop-Computer und wieder andere nutzen ein kleines Mobilgerät. Alle Besucher sollten das Menü öffnen und schließen können.

Demo für responsives Layout von Desktop zu Mobilgerät
Helles und dunkles Design unter iOS und Android

Webtaktik

In dieser explorativen Datenanalyse habe ich einige wichtige Webplattformfunktionen kombiniert:

  1. Preisvergleichsportal :target
  2. CSS-Raster
  3. CSS-transforms
  4. CSS-Medienabfragen für Darstellungsbereich und Nutzereinstellungen
  5. JS für focus UX-Verbesserungen

Meine Lösung hat eine Seitenleiste und kann nur umgeschaltet werden, wenn sie sich in einem mobilen Darstellungsbereich von 540px oder weniger befindet. 540px ist unser Haltepunkt für den Wechsel zwischen dem interaktiven Layout für Mobilgeräte und dem statischen Desktop-Layout.

CSS-:target-Pseudoklasse

Ein <a>-Link setzt den URL-Hash auf #sidenav-open und der andere auf leer (''). Schließlich verfügt ein Element über die id, die mit dem Hash übereinstimmt:

<a href="#sidenav-open" id="sidenav-button" title="Open Menu" aria-label="Open Menu">

<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu"></a>

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

Wenn Sie auf jeden dieser Links klicken, ändert sich der Hash-Status der Seiten-URL. Mit einer Pseudoklasse blende ich die Sidenav ein und aus:

@media (max-width: 540px) {
  #sidenav-open {
    visibility: hidden;
  }

  #sidenav-open:target {
    visibility: visible;
  }
}

CSS-Raster

Früher habe ich nur absolute oder feste SideNav-Layouts und -Komponenten verwendet. Mit „Grid“ können wir mit seiner grid-area-Syntax derselben Zeile oder Spalte mehrere Elemente zuweisen.

Stapel

Das primäre Layoutelement #sidenav-container ist ein Raster, das eine Zeile und zwei Spalten erstellt, von denen jeweils eine den Namen stack hat. Wenn der Platz beschränkt ist, weist CSS alle untergeordneten Elemente des <main>-Elements demselben Rasternamen zu. Dadurch werden alle Elemente im selben Bereich platziert und es wird ein Stapel erstellt.

#sidenav-container {
  display: grid;
  grid: [stack] 1fr / min-content [stack] 1fr;
  min-height: 100vh;
}

@media (max-width: 540px) {
  #sidenav-container > * {
    grid-area: stack;
  }
}

<aside> ist das Animationselement, das die seitliche Navigationsleiste enthält. Sie hat zwei untergeordnete Elemente: den Navigationscontainer <nav> namens [nav] und einen Hintergrund-<a> namens [escape], mit dem das Menü geschlossen wird.

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

Passe 2fr und 1fr an, um das gewünschte Seitenverhältnis für das Menü-Overlay und die Schließen-Schaltfläche mit Negativraum festzulegen.

Eine Demo dazu, was passiert, wenn du das Seitenverhältnis änderst.

CSS-3D-Transformationen und -Übergänge

Unser Layout ist jetzt für die Größe eines mobilen Darstellungsbereichs gestapelt. Bis ich neue Stile hinzugefügt habe, überlagert es standardmäßig unseren Artikel. Hier sind einige UX-Designs, auf die ich im nächsten Abschnitt stehe:

  • Öffnen und Schließen animieren
  • Nur mit Bewegung animieren, wenn der Nutzer damit einverstanden ist
  • Animieren Sie „visibility“, damit der Tastaturfokus nicht in das nicht sichtbare Element eindringt

Wenn ich mit der Implementierung von Bewegungsanimationen beginne, steht die Barrierefreiheit an erster Stelle.

Barrierefreie Bewegung

Nicht jeder wünscht sich eine rutschende Bewegung. In unserer Lösung wird diese Einstellung angewendet, indem die CSS-Variable --duration in einer Medienabfrage angepasst wird. Dieser Medienabfragewert repräsentiert die Betriebssystempräferenz eines Nutzers für Bewegung (falls verfügbar).

#sidenav-open {
  --duration: .6s;
}

@media (prefers-reduced-motion: reduce) {
  #sidenav-open {
    --duration: 1ms;
  }
}
Demo der Interaktion mit und ohne angewendete Dauer.

Wenn die seitliche Navigationsleiste geöffnet und geschlossen wird und ein Nutzer eine geringere Bewegung vorzieht, verschiebe ich das Element sofort in den sichtbaren Zustand. Der Zustand bleibt ohne Bewegung erhalten.

Übergang, Transformieren, Übersetzen

Seitliche Navigationsleiste (Standard)

Um den Standardstatus der Sidenav-Navigation auf Mobilgeräten zu deaktivieren, platziere ich das Element mit transform: translateX(-110vw).

Hinweis: Ich habe dem typischen Off-Screen-Code von -100vw ein weiteres 10vw hinzugefügt, damit die box-shadow der seitlichen Navigationsleiste nicht in den Hauptdarstellungsbereich eingeblendet wird, wenn dieser ausgeblendet ist.

@media (max-width: 540px) {
  #sidenav-open {
    visibility: hidden;
    transform: translateX(-110vw);
    will-change: transform;
    transition:
      transform var(--duration) var(--easeOutExpo),
      visibility 0s linear var(--duration);
  }
}
Sidenav in

Wenn das #sidenav-Element mit :target übereinstimmt, legen Sie die translateX()-Position auf die Homebase 0 fest und beobachten Sie, wie CSS das Element von seiner Außenposition von -110vw zu seiner "In"-Position von 0 über var(--duration) verschiebt, wenn der URL-Hash geändert wird.

@media (max-width: 540px) {
  #sidenav-open:target {
    visibility: visible;
    transform: translateX(0);
    transition:
      transform var(--duration) var(--easeOutExpo);
  }
}

Sichtbarkeit der Umstellung

Das Ziel ist nun, das Menü vor Screenreadern zu verbergen, wenn es außer Haus ist, damit Systeme den Fokus nicht auf ein nicht sichtbares Menü fokussieren. Dazu lege ich einen Sichtbarkeitsübergang fest, wenn sich :target ändert.

  • Beim Eingehen sollte keine Übergangssichtbarkeit erfolgen. Sie sollten sofort sichtbar sein, damit ich sehen kann, dass sich das Element öffnet und der Fokus akzeptiert wird.
  • Beim Ausgehen wird der Übergang mit der Sichtbarkeit verzögert, sodass er am Ende des Übergangs zu hidden wechselt.

UX-Verbesserungen der Barrierefreiheit

Diese Lösung stützt sich auf das Ändern der URL, damit der Status verwaltet wird. Natürlich sollte hier das Element <a> verwendet werden, das einige nützliche Bedienungshilfen kostenlos erhält. Wir zeichnen unsere interaktiven Elemente mit Beschriftungen aus, die die Absicht klar artikulieren.

<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu"></a>

<a href="#sidenav-open" id="sidenav-button" class="hamburger" title="Open Menu" aria-label="Open Menu">
  <svg>...</svg>
</a>
Eine Demo der User Experience für Voiceover und Tastaturinteraktion.

Jetzt geben unsere primären Interaktionsschaltflächen sowohl für die Maus als auch für die Tastatur klar ihre Absicht an.

:is(:hover, :focus)

Mit diesem praktischen CSS-Funktions-Pseudoselektor können wir unsere Hover-Stile schnell einbeziehen, indem wir sie auch mit Fokus teilen.

.hamburger:is(:hover, :focus) svg > line {
  stroke: hsl(var(--brandHSL));
}

JavaScript verwenden

Zum Schließen escape drücken

Mit der Taste „Escape“ auf deiner Tastatur sollte das Menü geschlossen werden. Ist das richtig? Verkabeln wir das jetzt.

const sidenav = document.querySelector('#sidenav-open');

sidenav.addEventListener('keyup', event => {
  if (event.code === 'Escape') document.location.hash = '';
});
Browserverlauf

Damit beim Öffnen und Schließen nicht mehrere Einträge im Browserverlauf gestapelt werden, fügen Sie der Schließen-Schaltfläche folgenden JavaScript-Code inline hinzu:

<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu" onchange="history.go(-1)"></a>

Dadurch wird der URL-Verlauf beim Schließen entfernt, sodass es so aussieht, als wäre das Menü nie geöffnet worden.

Fokus auf UX legen

Mit dem nächsten Snippet wird der Fokus auf die Öffnen- und Schließen-Schaltflächen gelegt. Ich möchte das Wechseln einfach machen.

sidenav.addEventListener('transitionend', e => {
  const isOpen = document.location.hash === '#sidenav-open';

  isOpen
      ? document.querySelector('#sidenav-close').focus()
      : document.querySelector('#sidenav-button').focus();
})

Wenn die seitliche Navigationsleiste geöffnet wird, fokussieren Sie die Schaltfläche zum Schließen. Wenn die seitliche Navigationsleiste geschlossen wird, fokussieren Sie die Schaltfläche zum Öffnen. Dazu rufe ich in JavaScript focus() für das Element auf.

Fazit

Jetzt, da du weißt, wie ich das gemacht habe, wie würdest du es tun?! So entsteht eine unterhaltsame Komponentenarchitektur! Wer erstellt die erste Version mit Slots? 🙂

Lassen Sie uns unsere Ansätze diversifizieren und alle Möglichkeiten kennenlernen, wie wir das Web entwickeln können. Erstelle einen Glitch, twittere mir deine Version und füge sie dem Abschnitt Community-Remixe unten hinzu.

Community-Remixe