Responsive Menu Concepts

Avatar of Tim Pietrusky
Tim Pietrusky am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Der folgende Beitrag ist ein Gastbeitrag von Tim Pietrusky. Ich kenne Tim von seiner produktiven Arbeit auf CodePen und davon, dass er dort ein hilfreiches Community-Mitglied ist. Er hat mir diesen Gastbeitrag über responsive Menüs geschrieben, den ich gerne unten mit Ihnen teile. Nicht nur ist es ein zeitgemäßes Konzept, sondern eines der Konzepte verbessert einen cleveren CSS-Trick, den wir hier bereits behandelt haben.

Wenn es um responsives Design geht, stehen wir vor verschiedenen Techniken, wie wir unsere Navigationsmenüs für kleine Bildschirme am besten anpassen können. Die Ressourcen scheinen endlos. Deshalb werde ich Ihnen vier Hauptkonzepte vorstellen und die Vor- und Nachteile aller diskutieren.

Drei davon sind aus reinem CSS und eines verwendet eine einzige Zeile JavaScript.

Bevor wir beginnen

Im Code, der in diesem Artikel vorgestellt wird, verwende ich keine Vendor-Präfixe, um das CSS leichter sichtbar und verständlich zu halten. Die komplexeren CSS-Beispiele verwenden SCSS. Jedes Beispiel wird auf CodePen gehostet, wo Sie bei Bedarf das kompilierte CSS sehen können.

Alle Menükonzepte in diesem Artikel basieren auf dieser einfachen HTML-Struktur, die ich Basic Menu nenne. Das Attribut role wird verwendet, um das jeweilige Konzept zu spezifizieren (full-horizontal, select, custom-dropdown und off-canvas).

<nav role="">
  <ul>
    <li><a href="#">Stream</a></li>
    <li><a href="#">Lab</a></li>
    <li><a href="#">Projects</a></li>
    <li><a href="#">About</a></li>
    <li><a href="#">Contact</a></li>
  </ul>
</nav>​

Um kleine Bildschirme zu adressieren, verwende ich bei allen Konzepten dieselbe Media Query.

@media screen and (max-width: 44em) {

}

1. Full Horizontal

Dies ist der einfachste Ansatz, da Sie die Listen-Elemente auf kleinen Bildschirmen einfach vollbreit machen müssen.

<nav role="full-horizontal">
  <ul>
    <li><a href="#">Stream</a></li>
    <li><a href="#">Lab</a></li>
    <li><a href="#">Projects</a></li>
    <li><a href="#">About</a></li>
    <li><a href="#">Contact</a></li>
  </ul>
</nav>​
@media screen and (max-width: 44em) {
  nav[role="full-horizontal"] {
    ul > li {
      width: 100%;
    }
  }
}

So sieht es auf einem kleinen Bildschirm mit individuellem Stil aus.

full-horz

Vorteile

  • Kein JavaScript
  • Kein zusätzliches HTML
  • Einfaches CSS

Nachteile

  • Verbraucht zu viel Bildschirmfläche

Demo

Auf CodePen

2. Select

Dieses Konzept verbirgt das Basis-Menü auf kleinen Bildschirmen und zeigt stattdessen ein Select-Menü an.

Um dies zu erreichen, müssen wir unser Basis-Markup erweitern und ein Select hinzufügen. Um das Select zum Laufen zu bringen, fügen wir auch etwas JavaScript hinzu, das window.location.href ändert, wenn das onchange-Ereignis des Selects auftritt.

<nav role="select">
  <!-- basic menu goes here -->
  
  <select onchange="if (this.value) window.location.href = this.value;">
    <option value="#">Stream</option>
    <option value="#">Lab</option>
    <option value="#">Projects</option>
    <option value="#">About</option>
    <option value="#">Contact</option>
  </select>
</nav>​

Wir verstecken das Select auf großen Bildschirmen.

nav[role="select"] {
  > select {
    display:none;  
  }
}

Auf kleinen Bildschirmen verstecken wir das Basis-Menü und zeigen das Select an. Um dem Benutzer zu helfen, zu erkennen, dass es sich um ein Menü handelt, fügen wir auch ein Pseudo-Element mit dem Text „Menu“ hinzu.

@media screen and (max-width: 44em) {
  nav[role="select"] {
    ul {
      display: none;
    }

    select {
      display: block;
      width: 100%;
    }

    &:after {
      position: absolute;
      content: "Menu";
      right: 0;
      bottom: -1em;
    }
  }
}

So sieht es auf einem kleinen Bildschirm mit individuellem Stil aus.

num-2

Vorteile

  • Benötigt nicht viel Platz
  • Verwendet native Steuerelemente

Nachteile

  • Benötigt JavaScript
  • Duplizierter Inhalt
  • Select ist nicht in jedem Browser gestaltbar

Demo

Auf CodePen

3. Custom Dropdown

Dieses Konzept verbirgt das Basis-Menü auf kleinen Bildschirmen und zeigt stattdessen ein Input & Label (um den Checkbox Hack zu verwenden). Wenn der Benutzer auf das Label klickt, wird das Basis-Menü darunter angezeigt.

<nav role="custom-dropdown">
    <!-- Advanced Checkbox Hack (see description below) -->
    
    <!-- basic menu goes here -->
</nav>​

Problem mit dem Checkbox Hack

Es gibt zwei Probleme mit dem Standard-Checkbox-Hack

  1. Funktioniert nicht auf mobiler Safari (iOS < 6.0). Aufgrund eines Fehlers ist es unter iOS < 6.0 nicht möglich, auf das Label zu klicken, um den Input zu schalten. Die einzige Lösung ist, dem Label ein leeres onclick hinzuzufügen.
  2. Funktioniert nicht im Standard-Android-Browser (Android <= 4.1.2). Vor langer Zeit gab es einen WebKit Adjacent/General Sibling & Pseudo Class Bug, der die Verwendung von Pseudoklassen in Kombination mit Adjacent (+) oder General (~) Sibling-Kombinatoren verhinderte.
h1 ~ p { color: black; }
h1:hover ~ p { color: red; }

Dies hat keine Auswirkung, da der Checkbox-Hack die Pseudoklasse :checked in Kombination mit dem General Sibling verwendet. Und da dies in WebKit 535.1 (Chrome 13) behoben wurde und das aktuelle WebKit auf Android 4.1.2 534.30 ist, funktioniert der normale Checkbox-Hack bis heute auf keinem Android-Gerät.

Die beste Lösung ist, eine nur für WebKit geltende Fake-Animation auf das Body-Element anzuwenden.

Alle Dinge zusammen ergeben den Advanced Checkbox Hack

<!-- Fix for iOS -->
<input type="checkbox" id="menu">
<label for="menu" onclick></label>
/* Fix for Android */
body { 
  -webkit-animation: bugfix infinite 1s; 
}
@-webkit-keyframes bugfix { 
  from { padding: 0; } 
  to { padding: 0; } 
}

/* default checkbox */
input[type=checkbox] {
  position: absolute;
  top: -9999px;
  left: -9999px;
}

label { 
  cursor: pointer;
  user-select: none;
}

Referenz: Advanced Checkbox Hack

Für große Bildschirme verstecken wir das Label

nav[role="custom-dropdown"] {
  label {
    display: none;
  }
}

Für kleine Bildschirme verstecken wir das Basis-Menü und zeigen das Label an. Um dem Benutzer zu helfen, zu erkennen, dass es sich um ein Menü handelt, fügen wir dem Label auch ein Pseudo-Element mit dem Text „≡“ (konvertiert zu „\2261“, um es als Inhalt des Pseudo-Elements zu verwenden) hinzu. Wenn der Benutzer auf das Input klickt, wird das Basis-Menü angezeigt und die Listen-Elemente werden auf volle Breite erweitert.

@media screen and (max-width: 44em) {
  nav[role="custom-dropdown"] {
    ul {
      display: none;
      height: 100%;
    }

    label {
      position: relative;
      display: block;
      width: 100%;
    }

    label:after {
        position: absolute;
        content: "\2261";
    }
    
    input:checked ~ ul {
      display: block;
    
      > li {
        width: 100%;
      }        
    }
  }
}

So sieht das Menü auf einem kleinen Bildschirm mit individuellem Stil aus.

closed
Geschlossen
open
Geöffnet

Vorteile

  • Benötigt im geschlossenen Zustand nicht viel Platz
  • Benutzerdefinierte Formatierung
  • Kein JavaScript

Nachteile

  • Schlechte Semantik (Input / Label)
  • Zusätzliches HTML

Demo

Auf CodePen

4. Off Canvas

Dieses Konzept verbirgt das Basis-Menü auf kleinen Bildschirmen und zeigt stattdessen ein HTML-Input & Label (um den Advanced Checkbox Hack zu verwenden, siehe 3. Custom Dropdown für weitere Infos). Wenn der Benutzer auf das Label klickt, fliegt das Basis-Menü von links herein und der Inhalt bewegt sich nach rechts – der Bildschirm wird geteilt: Menü ~80 % und Inhalt ~20 % (abhängig von Auflösung und CSS-Einheiten).

<input type="checkbox" id="menu">
<label for="menu" onclick></label>

<!-- basic menu goes here -->

<div class="content">
  <!-- content goes here -->
</div>

Auf großen Bildschirmen verstecken wir das Label.

label {
  position: absolute;
  left: 0;
  display: none;
}

Auf kleinen Bildschirmen verstecken wir das Basis-Menü außerhalb des Viewports und zeigen das Label / Input an. Um das Menü zu verstecken, geben wir eine Breite ($menu_width) an und addieren eine negative Position dazu. Um dem Benutzer zu helfen, zu erkennen, dass es sich um ein Menü handelt, fügen wir dem Label auch ein Pseudo-Element mit dem Text „≡“ (konvertiert zu „\2261“, um es als Inhalt des Pseudo-Elements zu verwenden) hinzu. Wenn der Benutzer auf das Input klickt, fliegt das Basis-Menü von links herein und der Inhalt bewegt sich nach rechts.
Wenn der Benutzer auf das Input klickt, fliegt das Basis-Menü von links herein und der Inhalt bewegt sich nach rechts.

@media screen and (max-width: 44em) {
  $menu_width: 20em;

  body {
    overflow-x: hidden;
  }
    
  nav[role="off-canvas"] {
    position: absolute;
    left: -$menu_width;
    width: $menu_width;
    
    ul > li {
      width: 100%;
    }
  }

  label {
    display: block;
  }

  label:after {
    position: absolute;
    content: "\2261";
  }

  input:checked ~ nav[role="off-canvas"] {
    left: 0;
  }

  input:checked ~ .content {
    margin-left: $menu_width + .5em;
    margin-right: -($menu_width + .5em);
  }
}​

So sieht das Menü auf einem kleinen Bildschirm mit individuellem Stil aus.

offcanvas-closed
Geschlossen
offcanvas-open
Geöffnet

Vorteile

  • Benötigt im geschlossenen Zustand nicht viel Platz
  • Benutzerdefinierte Formatierung
  • Kein JavaScript
  • Konvention von Facebook / Google+ App

Nachteile

  • Schlechte Semantik (Input / Label)
  • Zusätzliches HTML
  • Absolute Positionierung zum Body = Fühlt sich wie Fixed Position an

Demo

Auf CodePen

Funktioniert das auf IE?

Alle oben genannten Techniken haben ein Ziel: Responsive Menüs für moderne Browser erstellen! Und weil es auf keinem mobilen Gerät IE 8 oder niedriger gibt, müssen wir uns darum keine Sorgen machen.