Codelab: Sidenav-Komponente erstellen

In diesem Codelab erfahren Sie, wie Sie eine responsive Layoutkomponente für ein ausblendbares seitliches Navigationslayout im Web erstellen. Wir erstellen die Komponente nach und nach, beginnend mit HTML, dann CSS und zuletzt JavaScript.

In meinem Blogpost Building a Sidenav component (Eine Seitenleiste erstellen) erfahren Sie mehr über die Funktionen der CSS-Webplattform, die für die Erstellung dieser Komponente ausgewählt wurden.

Einrichtung

  1. Klicke auf Remix zum Bearbeiten, um das Projekt bearbeitbar zu machen.
  2. Öffnen Sie app/index.html.

HTML

Machen Sie sich zuerst mit den Grundlagen der HTML-Einrichtung vertraut, damit Sie Inhalte und Felder zum Arbeiten haben.

Lege den folgenden HTML-Code in das <body>-Tag ein.

<aside></aside>
<main></main>

Das <aside> enthält das Navigationsmenü als ergänzendes Element zu <main>, das den Hauptinhalt der Seite enthält.

Als Nächstes füllen wir diese semantischen Elemente mit dem restlichen Seiteninhalt.

Fügen Sie dem <aside>-Element ein Navigationselement, einige Navigationslinks und einen Schließen-Link hinzu.

<aside>
  <nav>
    <h4>My</h4>
    <a href="#">Dashboard</a>
    <a href="#">Profile</a>
    <a href="#">Preferences</a>
    <a href="#">Archive</a>

    <h4>Settings</h4>
    <a href="#">Accessibility</a>
    <a href="#">Theme</a>
    <a href="#">Admin</a>
  </nav>

  <a href="#"></a>
</aside>

Links eignen sich hervorragend für <nav>-Elemente und <nav>-Elemente für <aside>-Seitenleisten. Es gibt jedoch noch Verbesserungsmöglichkeiten.

Fügen Sie dem Hauptinhaltselement eine Überschrift und einen Artikel hinzu, um den Layoutinhalt semantisch zu speichern.

<main>
  <header>
    <a href="#sidenav-open" class="hamburger">
      <svg viewBox="0 0 50 40">
        <line x1="0" x2="100%" y1="10%" y2="10%" />
        <line x1="0" x2="100%" y1="50%" y2="50%" />
        <line x1="0" x2="100%" y1="90%" y2="90%" />
      </svg>
    </a>
    <h1>Site Title</h1>
  </header>

  <article>
    {put some placeholder content here}
  </article>
</main>

In der Kopfzeile ist der Link zum Öffnen des Menüs zu sehen. In der Seitenleiste befindet sich die Schaltfläche „Schließen“. Bald werden Elemente basierend auf der Größe des Darstellungsbereichs angezeigt und ausgeblendet.

Im <article>-Element haben wir einen Platzhaltersatz eingefügt. Ersetzen Sie „“ durch Ihre eigenen Inhalte oder fügen Sie das unten stehende Lorem ipsum ein:

<h2>Totam Header</h2>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Cum consectetur, necessitatibus velit officia ut impedit veritatis temporibus soluta? Totam odit cupiditate facilis nisi sunt hic necessitatibus voluptatem nihil doloribus! Enim.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>

<h3>Subhead Totam Odit</h3>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>

<h3>Subhead</h3>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>

Dieser Inhalt und seine Länge führen dazu, dass die Seite gescrollt werden kann, wenn sie die Höhe Ihres Darstellungsbereichs überschreitet.

Bisher haben Sie ein Aside-Element mit einer Navigation, Links und einer Möglichkeit zum Schließen der seitlichen Navigationsleiste hinzugefügt. Außerdem haben Sie dem Hauptelement eine Überschrift, eine Möglichkeit zum Öffnen der Seitenleiste und einen Artikel hinzugefügt. Das Design ist bereits klar, semantisch und ziemlich zeitlos, aber wir können es für alle noch übersichtlicher und klarer gestalten. Der Link in der seitlichen Navigationsleiste könnte deutlicher gekennzeichnet sein.

Fügen Sie dem Kopfzeilen-Link-Element die Attribute title und aria-label hinzu:

<a href="#sidenav-open" class="hamburger">
<a href="#sidenav-open" title="Open Menu" aria-label="Open Menu" class="hamburger">

Das Symbol für geöffnete SVG-Dateien könnte auch deutlicher gekennzeichnet sein. Fügen Sie dem SVG innerhalb des Elements „open link“ die folgenden Attribute hinzu:

<svg viewBox="0 0 50 40">
<svg viewBox="0 0 50 40" role="presentation" focusable="false" aria-label="trigram for heaven symbol">

Der Link zum Schließen in der Seitenleiste könnte deutlicher gekennzeichnet sein. Fügen Sie die Attribute title und aria-label dem Element zum Schließen von Sidenav hinzu:

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

CSS

Jetzt ist es an der Zeit, die Elemente anzuordnen. Der Hauptinhalt und die Seitenleiste sind direkt untergeordnet und daher ein guter Ausgangspunkt.

Fügen Sie css/sidenav.css das folgende CSS hinzu, damit die untergeordneten Elemente vom <body>-Element angeordnet werden.

body {
  display: grid;
  grid: [stack] 1fr / min-content [stack] 1fr;

  @media (max-width: 540px) {
    & > :matches(aside, main) {
      grid-area: stack;
    }
  }
}

Dieses Layout bedeutet im Wesentlichen: Erstellen Sie eine benannte Zeile stack mit allen Inhalten und zwei Spalten in dieser Zeile, von denen die zweite ebenfalls stack heißt. Die Größe der ersten Spalte sollte an den minimalen Inhaltsanforderungen ausgerichtet sein. Die zweite Spalte kann den Rest einnehmen. Platzieren Sie dann in einem eingeschränkten Darstellungsbereich von 540px oder weniger die Elemente der seitlichen Navigationsleiste und der Hauptinhalte in derselben Zeile und Spalte, sodass sie in einem 1 × 1-Raster übereinander liegen.

Mit dieser responsiven Stapelfunktion als Grundlage können wir jetzt den Status der URL-Leiste nutzen, um die Sichtbarkeit und den Übergangsstil der seitlichen Navigationsleiste umzuschalten.

Aktualisieren Sie das <aside>-Element in app/index.html:

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

So kann CSS ein Element und den URL-Hash miteinander abgleichen. Das ist wichtig für die Nutzung von :target. Jetzt kann die ID des Elements mit dem URL-Hash übereinstimmen, den wir mit <a>-Tags festlegen.

Fügen Sie außerdem für ein einfacheres JavaScript-Targeting IDs für wichtige Elemente hinzu, die die Seitenleiste steuern. Fügen Sie zuerst dem Link zum Öffnen der Seitenleiste eine ID hinzu:

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

Fügen Sie als Nächstes dem Link zum Schließen der Seitenleiste eine ID hinzu:

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

Damit wird das Makro <body> für responsives Stapellayout zusammengefasst und mit der URL-Leiste verknüpft. Weiter geht's!

<aside> hat auch ein übersichtliches Layout. Es hat zwei untergeordnete Elemente: ein <nav>, die papierartige Komponente, die herausgeschoben wird, und ein schließendes <a>-Linkelement, das die URL auf # festlegt. Der Link ist rechts neben der ausziehbaren Navigationsleiste nicht sichtbar. So können Nutzer die visuelle Komponente „ausklicken“, um sie zu schließen.

Fügen Sie css/sidenav.css das folgende CSS hinzu:

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

Ich fand das Verhältnis und die Namen hier sehr gelungen, da das Raster hier gut zur Geltung kommt und dem Designer viel Kontrolle bietet.

Als Nächstes muss ich den Hauptinhalt bedingt einblenden und meine Position beim Scrollen beibehalten. Das ist eine tolle Stelle für position: sticky und ein bisschen overscroll-behavior.

Fügen Sie die folgenden Stile für die Seitenleiste hinzu:

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

  @media (max-width: 540px) {
    position: sticky;
    top: 0;
    max-height: 100vh;
    overflow: hidden auto;
    overscroll-behavior: contain;

    visibility: hidden; /* not keyboard accessible when closed */
  }
}

Diese Stile sorgen dafür, dass die Seitenleiste die Höhe des Darstellungsbereichs hat, vertikal scrollt und das Scrollen enthält. Das Element wird ausgeblendet. Wenn der Darstellungsbereich 540px oder kleiner ist, wird die Seitenleiste standardmäßig ausgeblendet. Es sei denn…

Fügen Sie dem Element #sidenav-open einen :target-Pseudoselektor hinzu:

#sidenav-open {

  @media (max-width: 540px) {

    &:target {
      visibility: visible;
    }
  }
}

Wenn die ID dieses Elements und die URL-Leiste identisch sind, legen Sie visibility auf visible fest. Öffnen Sie das seitliche Menü, nachdem Sie auf der Seite gescrollt haben, oder scrollen Sie auf der Seite, während die Seitenleiste geöffnet ist. Was ist Ihre Meinung dazu?

Fügen Sie unten in app/sidenav.css das folgende CSS hinzu:

#sidenav-button,
#sidenav-close {
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  user-select: none;
  touch-action: manipulation;

  @media (min-width: 540px) {
    display: none;
  }
}

Diese Stile sind auf unsere Schaltflächen zum Öffnen und Schließen ausgerichtet, geben den Stil für das Tippen und Tippen an und werden auch ausgeblendet, wenn ein Darstellungsbereich 540px oder größer ist.

Fügen wir nun CSS-Transformationen mit einer respektvollen Zugänglichkeit hinzu. Fügen Sie css/sidenav.css das folgende CSS hinzu:

#sidenav-open {
  --easeOutExpo: cubic-bezier(0.16, 1, 0.3, 1);
  --duration: .6s;

  ...

  @media (max-width: 540px) {
    ...

    transform: translateX(-110vw);
    will-change: transform;
    transition:
      transform var(--duration) var(--easeOutExpo),
      visibility 0s linear var(--duration);

    &:target {
      visibility: visible;
      transform: translateX(0);
      transition: transform var(--duration) var(--easeOutExpo);
    }
  }

  @media (prefers-reduced-motion: reduce) {
    --duration: 1ms;
  }
}
Eine Demo der Interaktion mit und ohne angewendete Dauer basierend auf der Medienabfrage „prefers-reduced-motion“.

Ein bisschen JavaScript

Mit der Taste Escape sollte das Menü geschlossen werden. Fügen Sie js/index.js dieses JS-Script hinzu:

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

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

Wartet auf ein Schlüsselereignis im Element „sidenav“. Bei Escape wird der URL-Hash auf einen leeren Wert gesetzt, sodass die seitliche Navigationsleiste außer Acht gelassen wird.

Der nächste Teil von UX JS ist die Fokusverwaltung. Ich möchte das Öffnen und Schließen so einfach wie möglich gestalten. Deshalb warte ich, bis die Seitenleiste eine Art Übergang abgeschlossen hat, und prüfe dann anhand des URL-Hashes, ob sie eingeblendet oder ausgeblendet ist. Dann verwende ich JavaScript, um den Fokus auf die Schaltfläche zu richten, die der gerade angeklickten

Fügen Sie js/index.js das folgende JavaScript hinzu:

const closenav = document.querySelector('#sidenav-close');
const opennav = document.querySelector('#sidenav-button');

sidenav.addEventListener('transitionend', e => {
  if (e.propertyName !== 'transform') {
    return;
  }

  const isOpen = document.location.hash === '#sidenav-open';

  isOpen
    ? closenav.focus()
    : opennav.focus();
});

Jetzt ausprobieren

  • Wenn Sie sich eine Vorschau der Website ansehen möchten, drücken Sie App ansehen und dann Vollbild Vollbild.

Fazit

Das war es mit meinen Anforderungen an die Komponente. Sie können darauf aufbauen, sie mit dem JavaScript-Status anstelle der URL ausführen und sie im Allgemeinen an Ihre Anforderungen anpassen. Es gibt immer noch mehr zu ergänzen oder weitere Anwendungsfälle.

Öffnen Sie css/brandnav.css, um sich die nicht layoutbezogenen Stile anzusehen, die ich auf diese Komponente angewendet habe. Ich fand es für die Funktionen, auf die ich mich konzentrierte, nicht wichtig und hoffte, dass die Trennung von Stilen und Layout das Kopieren und Einfügen fördern würde. Dort gibt es möglicherweise noch mehr zu lernen.

Wie erstelle ich ausziehbare responsive Seitenleisten? Haben Sie manchmal mehr als eine, z. B. eine auf beiden Seiten? Ich würde deine Lösung gerne in einem YouTube-Video vorstellen. Tweete mir einfach deinen Code oder kommentiere ihn in einem YouTube-Video. Das hilft allen!