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.

Vorteile
- Kein JavaScript
- Kein zusätzliches HTML
- Einfaches CSS
Nachteile
- Verbraucht zu viel Bildschirmfläche
Demo
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.

Vorteile
- Benötigt nicht viel Platz
- Verwendet native Steuerelemente
Nachteile
- Benötigt JavaScript
- Duplizierter Inhalt
- Select ist nicht in jedem Browser gestaltbar
Demo
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
- 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.
- 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.


Vorteile
- Benötigt im geschlossenen Zustand nicht viel Platz
- Benutzerdefinierte Formatierung
- Kein JavaScript
Nachteile
- Schlechte Semantik (Input / Label)
- Zusätzliches HTML
Demo
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.


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
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.
Danke für diesen Artikel, eine Anmerkung allerdings
Anstatt des Checkbox-Hacks ist es möglich, die :target-Pseudoklasse zu verwenden
Siehe Raphael Goetters Experimente hier: http://thinkmobilefirst.net/nav/
Ich bin mir spezifischer Gerätebeschränkungen nicht bewusst, ich hätte gerne Feedback dazu, ich habe es gerade auf
http://www.rescue2014.fr (Browserfenster skalieren, offensichtlich)
:target ist ideal für Semantik, aber ein Nachteil, da es Verlaufs-Elemente hinzufügt (beeinflusst die Zurück-Taste).
:checked ist semantisch weniger gut, aber funktional besser.
Schwierige Situation.
Dies wäre ein Fall, in dem ich dazu neigen würde, die Semantik zu verwerfen. Wir sind wahrscheinlich die Einzigen, die die Semantik sehen und sich tatsächlich darum kümmern werden, und die nicht-semantische Version funktioniert besser. Also würde ich eher das verwenden, was funktioniert. Der durchschnittliche Benutzer der Website wird den Code wahrscheinlich nicht sehen und, wenn er ihn sieht, sich wahrscheinlich nicht um Semantik kümmern.
@cnwtx
Wahr, aber benutzerfreundlichere Agenten (Screenreader usw.) verlassen sich auf Semantik, um die Elemente der Website zu finden, die der Benutzer anzeigen/lesen möchte.
@Ando, Wahr, aber ich würde denken, dass Screenreader usw. eher das <nav> anstelle von :checked oder :target sehen werden. Sie haben aber sicherlich einen guten Punkt angesprochen.
@cwntx
Ja, ehrlich gesagt bin ich mir nicht ganz sicher, wie Screenreader mit Inputs und Labels innerhalb eines Nav-Tags funktionieren würden. Könnte beides sein, soweit ich weiß, haha.
Super Artikel Tim! Sehr klar und bietet viele Wege, um eine Sache zu tun, das gefällt mir.
Übrigens, diese Ergänzung des Checkbox-Hacks ist komplett verrückt, ich frage mich, wie man überhaupt auf so etwas kommen kann!
Viel alte Versuch-und-Irrtum-Arbeit über viele Stunden auf verschiedenen Plattformen mit Hilfe von BrowserStack. Ich wollte nur, dass es überall funktioniert.
Ich denke, die Verwendung des Attributs „role“ ist keine gute Idee, Sie können stattdessen data-* Attribute verwenden.
http://www.w3.org/TR/xhtml-role/
http://ejohn.org/blog/html-5-data-attributes/
Ich werde über die Verwendung von data- anstelle von role-Attributen nachdenken! Danke.
Ich stimme dem voll und ganz zu, es ist das erste, was mir aufgefallen ist.
rolesollte den Zweck eines Elements definieren (auf maschinenlesbare Weise), aber hier verwenden Sie es, um die Darstellung des Elements zu definieren.Wie @Israel vorschlägt, wäre die Verwendung von
data-*-Attributen (oder sogar einerclass) besser geeignet.Tolle Zusammenfassung! Ich werde hier wahrscheinlich 1000 Mal in Zukunft herkommen.
Es scheint, dass diese Stilgruppen auf einer einfachen HTML-Klasse basieren könnten und nicht auf dem role-Attribut. Das role-Attribut ist typischerweise, wenn auch nicht ausschließlich, für ARIA-Rollen reserviert, die bereits verwirrend sind, aber eine Reihe von vordefinierten Rollen sind, die für andere Maschinen eine Bedeutung haben.
Ich wusste nicht, dass das role-Attribut für ARIA-Rollen reserviert ist. Danke für die Info!
Nicht technisch reserviert per se, aber es erfüllt seinen Zweck für ARIA / Screenreader etc. Was Sie getan haben, war technisch nicht falsch, da Sie einfach nach Attribut ausgewählt haben, aber ich bin sicher, andere werden Ihnen den „data-“ HTML5-Attribut-Ansatz empfehlen, da er speziell dafür entwickelt wurde, Dinge so zu handhaben, wie Sie es möchten. Worauf Sie bei HTML5-benutzerdefinierten Datenattributen achten müssen, ist, dass Plugins/Bibliotheken möglicherweise dieselben Namenskonventionen verwenden, ohne dass Sie es merken. Eine ausreichend standardisierte Namenskonvention wie img src=”” data-index=”0″ alt=”Bobs Hair” könnte in Ihrer Anwendung in Konflikt geraten, seien Sie also vorsichtig mit Ihren Namenskonventionen.
Einige großartige Lösungen dort, die mir viele Ideen und Dinge geben, die ich ausprobieren möchte.
Hier ist eine, an der ich gearbeitet habe, sie benötigt kein JavaScript, ist aber mit JavaScript etwas schöner. Alles ist auf GitHub, also wenn jemand es verwenden/basteln möchte, nur zu :)
martinblackburn.github.com/responsive-nav/
Wenn ich den Checkbox-Hack mache, um den iOS-Bug zu umgehen, style ich stattdessen den
<input>mit(-prefix-)appearance: none;am Anfang, um das Standard-Styling zu überschreiben.Der iOS-Bug hat nichts mit Styling zu tun. Er verhindert, dass Sie auf das
labelklicken, um deninputzu schalten (angehakt / nicht angehakt). Und wenn Sie den Bug beheben wollen, könnten Sie ein leeresonclickzumlabelhinzufügen oder deninput(mit voller Höhe/Breite) vor das Label legen.Der Punkt, den ich machen wollte, ist, dass man kein Label braucht, wenn man den
inputstylt. Ich weiß, dass es nicht ums Styling geht. Sie können immer noch das Icon mit einem::beforehaben und vielleicht sogar ein versteckteslabelfür SEO, aber es beseitigt die Notwendigkeit dieses leerenonclick.Jetzt verstehe ich, was Sie meinen. Das klingt nach einer wirklich coolen Verbesserung, um das Label loszuwerden. Aber leider wird es im neuesten Opera oder Internet Explorer 10 nicht unterstützt.
Das stimmt, obwohl ich denke, dass durch das Hinzufügen eines
borderdas Standard-Aussehen sowieso überschrieben wird (bei Textfeldern ist es so).@Martin: Ich habe etwas sehr Ähnliches gemacht, und es ist mein bevorzugter Ansatz. Aber das letzte im Beitrag (Off Canvas) ist ziemlich gut, ich schätze, ich werde eine Kombination machen, im Allgemeinen halte ich mich von Formularelementen für die Navigation fern.
Eine weitere Möglichkeit, wenn Sie nichts gegen ein wenig JavaScript haben, ist Brad Frosts Toggle-Methode anstelle des Checkbox-Hacks. Benötigt JavaScript, ist aber gut unterstützt. Ich habe eine Demo auf CodePen gemacht.
Sehr schön, Leute, danke.
Glenn
Großartig, ich lerne immer dazu, THX vielmals
Gute Arbeit, danke fürs Teilen.
Aber ich glaube nicht, dass Labels und Inputs oder Optionen semantisch für die Navigation richtig sind.
Was ist falsch mit Javascript und dem Hinzufügen einer Klasse in Nav? Warum ist das ein Nachteil? Einfaches Markup, sauberes CSS, einfaches JS.
Ich bin derselben Meinung. Ich denke, es wäre besser, Klassen mit einfachem Javascript anstelle von Formularelementen zu verwenden.
Der einzige Nachteil der Verwendung von JavaScript ist, dass es nicht funktioniert, wenn JavaScript deaktiviert ist.
Wie im Artikel beschrieben, ist die Hinzufügung von Label/Input nicht semantisch richtig. Es ist nur eine Möglichkeit, diese Art von Menü ohne JavaScript zu handhaben. Aber Sie können diese Konzepte nach Belieben erweitern! Denken Sie nur daran, sie mit der Community zu teilen.
Ich stimme zu, dass Javascript eine gute Lösung ist. Es umgeht die Unannehmlichkeiten von Formularelementen und/oder doppelten Inhalten. Wenn Sie Mobile First designen – mit vernünftigem Markup und Funktionalität für diejenigen ohne Javascript – sind Sie gut dran.
Meine Lösung für wirklich große oder komplexe Menüs ist, das Menü auf eine eigene Seite zu legen. Benutzer ohne Javascript, die auf den „Menü“-Button klicken, gelangen zur separaten Menüseite. Für diejenigen mit JS-Unterstützung lade ich das Menü per Ajax und verwende dann Javascript, um das Menü entsprechend zu verstecken und anzuzeigen.
Ich denke, die beste Option im Moment ist die erste Option, full horizontal.
Ja, es kann viel Bildschirmfläche einnehmen, wenn man viele Top-Level-Navigationspunkte hat, aber es ist die einzige, die keine anderen Nachteile hat.
Vielleicht werden wir in Zukunft besser semantisch korrekte Optionen haben, bis dahin ist diese Methode meiner Meinung nach die sicherste.
Gut geschrieben, Tim!
Wie Dave oben schrieb, ist dieser Artikel eine gute Erinnerung, die man beim Erstellen eines neuen responsiven Menüs beachten sollte.
Ist es möglich, Untermenüs hinzuzufügen?
Chris, es wäre interessant, die CodePen-Iframes skalieren zu können, damit wir die Media Queries in Aktion sehen können, ohne sie in einem anderen Tab öffnen zu müssen, und dann das Browserfenster skalieren zu müssen.
Es ist interessant und nützlich.
Tolle Menüs. :)
Gibt es eine Möglichkeit, dass SCSS in normales CSS umgewandelt wird?
Hallo, Wenn Sie dort klicken, wo SCSS in CodePen steht, wird es in CSS kompiliert.
Hallo – sehr gut geschriebener Beitrag!
Von Anfang an scheint dieser Beitrag für Desktop-First zu sein, mit mobilen Anpassungen, um die kleinen Bildschirme gut zu verhalten.
Führt dies zu einem besseren Gesamtergebnis als ein Mobile-First-Ansatz, bei dem alle Anpassungen den Desktop-Code besser performen lassen?
Meine Wahl wäre, das „Select“-Menü mit einem Fallback auf „Full Horizontal“ zu verwenden und JavaScript zu verwenden, um das „Select“-Menü anzuzeigen und das „Full Horizontal“ zu verbergen.
Die Beispiele funktionieren auf meinem iPhone nicht; ich bekomme nur die „vollformatige“ Seite.
Ist das eine Einschränkung von CodePen? Es erlaubt Ihnen nicht, das Viewport-Meta-Tag zu setzen?
Für mich ist die beste Lösung immer noch eine Kombination aus 1 und 3, oder man könnte sogar 1 und 4 machen. Das bedeutet, dass man ein Menü hat, das standardmäßig oben (oder unten) auf der Seite sichtbar ist, und das beim Laden der Seite mit JS in eine der anderen Lösungen umwandelt. Dann kann man JS-Events für Trigger verwenden und ist nicht auf den Checkbox-Hack angewiesen, der wie ein Hack eben nur ein Hack zu sein scheint. Danke für den Beitrag!
Großartig geschrieben, Tim! Und danke nochmal für deine Hilfe bei den Navigationsmenü-Plugins, an denen ich gearbeitet habe.
Perfekte Kategorisierung und Vergleich, wie immer!
Danke!
Wie @Vivek Nath.R oben erwähnt hat, behandeln keine der Beispiele Unternavigationen. Obwohl ich immer gerne Websites ohne Untermenü baue, ist das bei bestimmten Kunden (oder Websites) einfach nicht möglich. Eine große Herausforderung bei der responsiven Navigation scheint zu sein, wie man große Menüs handhabt. Brad Frost hat hier einige großartige Beispiele: here. Aber toller Beitrag, es ist schön zu sehen, wie CodePen so gut genutzt wird.
Es wäre wahrscheinlich gut gewesen, das Wort „mobil“ in den Titel des Beitrags aufzunehmen.
Sehr schön erklärter und detaillierter Artikel. Ich habe danach gesucht und werde definitiv den Custom Dropdown-Ansatz verwenden
PD. Wo ist der Share-Link?
Wie würde man ein Menü erstellen, das auf PCs Hover für Dropdowns und auf Mobilgeräten Klicks verwendet?