HTML / CSS: Das eigene responsive Menu ohne Javascript

Zuletzt aktualisiert am 25. Dezember 2023 von Lars

Fertige Bibilotheken für ein responsive Menu gibt es viele. Meist sind die recht schnell angepasst und in die eigene Homepage eingebaut. Was aber, wenn man von einem Grafiker ein Design für ein Menü vorgegeben bekommt und genau das nachbauen soll? Genau vor der Aufgabe stehe ich zur Zeit. Ich trage in diesem Artikel das nötige Wissen zusammen, so dass auch Ihr das könnt. CSS und HTML Kenntnisse sind aber notwendig. Ohne die wird es nicht gehen.

Bock auf JQuery und Javascript habe ich nicht, da ich es nicht besonders gut kann und keine zusätzlichen Skripte nachladen will.

Erster Versuch

Der Entwurf sah vor, dass auf einem normalen Gerät der Menübaum in einem Aufklappmenü zu sehen ist und auf einem mobilen Gerät in der üblichen Reihenfolge.

Ich gehe direkt mal auf meinen ersten Entwurf ein: 1.html

<!DOCTYPE html> 
<html lang="de">
<head>
<title></title>
<meta charset="utf-8" />
<link rel="stylesheet" href="1.css" type="text/css" media="screen" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<ul class="Lev1">
<li><a href="">MENU</a>
<ul class="Lev2">
<li><a href="">Rubrik 1</a>
<ul>
<li><a href="">Unterrubrik 1</a></li>
<li><a href="">Unterrubrik 2</a></li>
<li><a href="">Unterrubrik 3</a></li>
</ul>
</li>
<li><a href="">Rubrik 2</a>
<ul>
<li><a href="">Unterrubrik 1</a></li>
<li><a href="">Unterrubrik 2</a></li>
<li><a href="">Unterrubrik 3</a></li>
</ul>
</li>
<li><a href="">Rubrik 3</a>
<ul>
<li><a href="">Unterrubrik 1</a></li>
<li><a href="">Unterrubrik 2</a></li>
<li><a href="">Unterrubrik 3</a></li>
</ul>
</li>
</ul>
</li>

</ul>

<h1>Dies ist ein Powertext</h1>
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy 
eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam 
voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita 
kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem 
ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor 
invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos 
et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea 
takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, 
consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et 
dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo 
duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est 
Lorem ipsum dolor sit amet.
</p>

</body>
</html>

Hier das zugehörige 1.css

ul.Lev2
{
	display: none;
	position:absolute;  /* Absolute Positionierung, damit bei Hover-Effekt der Text darunter nicht verschoben wird */
}

ul.Lev1 li a:hover ~ ul
{
	display: block !important;
	border: 1px solid black; /* Rahmen drum rum */
	z-index: 9999999;		 /* Vor dem übrigen Text */
	background: white;		 /* Hintergrund weiss */
}

Was habe ich mir dabei gedacht?

Um CSS wird die unordered List (Klasse Lev2) erstmal ausgeblendet (display: none) und absolut postitioniert (positition : absolute). Im nächsten CSS-Block wird die unordered List eingeblendet, sobald man mit der Maus auf den Link Menu ist.

Was? Wie funktioniert das genau? Hier müssen wir uns einige CSS-Besonderheiten genauer anschauen. Bei den folgenden CSS-Selektoren sollten wir uns die HTML-Elemente innerhalb einer Baumstruktur vorstellen.

CSS - Descendent Selector

Ein Descendant Selector oder Nachfahren-Selektor filtert Elemente unterhalb eines bestimmten Elementes.

Beispiel:

<style>
#test p {color: red;}
</style>

<div id="test">
<p>Absatz 1</p>
<p>Absatz 2</p>
<p>Absatz 3</p>
<div>
<p>Absatz 4</p>
</div>
<p>Absatz 5</p>
</div>

Das kennen wir ja (hoffentlich) schon. Hier werden alle p in dem div #test angesprochen und rot gefärbt. Allgemeine gesagt alle Elemente, die in einem anderen enthalten sind.

CSS - Child Descendent Selector

Ein Child Descendant Selector oder Kind-Nachfahren-Selektor filtert Elemente direkt unterhalb eines bestimmten Elementes.

Beispiel:

<style>
#test>p {color: red;}
</style>

<div id="test">
<p>Absatz 1</p>
<p>Absatz 2</p>
<p>Absatz 3</p>
<div>
<p>Absatz 4</p>
</div>
<p>Absatz 5</p>
</div>

Hier werden nur die direkten Unterelemente p angesprochen (alle). Das p, das durch ein weiteres div vom darüberliegenden "abgetrennt" ist, bleibt ungefärbt, da es kein direktes "Kind" ist.

CSS - Adjacent Sibling Selector

Sibling steht für Geschwister. Adjacent Sibling Selectors oder angrenzende Geschwisterselektoren filtern Elemente, die aufeinander folgen und auf derselben Ebene liegen.

Beispiel:

<style>
#test h1+p {color: red;}
</style>

<div id="test">
<h1>Überschrift</h1>
<p>Absatz 1</p>
<p>Absatz 2</p>
<p>Absatz 3</p>
<div>
<p>Absatz 4</p>
</div>
<p>Absatz 5</p>
</div>

Der adjacent sibling combinator spricht ein Element an (im Beispiel p), das direkt hinter einem anderen Element hängt (an den Baum denken - im Beispiel h1). Wichtig ist, dass da Element wirklich direkt dem anderen folgen muss. Im obigen Beispiel wird also nur das erste (p) rot. Für das Verständnis unbedingt daran denken: p ist zwar optisch irgendwie unter h1 angelegt, liegt aber auf der gleichen Ebene. P würde elementmässig unter h1 liegen, wenn p in ein div gepackt ist.

CSS - General Sibling Combinator

Sibling steht für Geschwister. General Sibling Selectors oder generelle Geschwisterselektoren filtern Elemente, die aufeinander folgen und auf derselben Ebene liegen.

Beispiel:

<style>
h1 ~ p {color: red;}
</style>

<h1>Überschrift</h1>
<p>Absatz 1</p>
<p>Absatz 2</p>
<p>Absatz 3</p>
<p>Absatz 4</p>

Der general sibling combinator spricht alle Geschwister an, die es in der Baumstruktur gibt. Im Gegensatz zu dem adjacent sibling combinator muss das Element nicht direkt dem anderen folgen. Hier werden also alle p eingefärbt, bis auf das, was in einem weiteren div sitzt, den dass ist kein "Geschwister" mehr von h1.

Adam Khoury hat hierzu auch ein tolles Video gemacht. Zwar auf englisch, aber schön langsam gesprochen.

CSS Combinator Selectors

Das Video wird von YouTube eingebettet und erst beim Klick auf den Play-Button geladen. Es gelten die Datenschutzerklärungen von Google.

Auf mediaevent.de ist das Ganze mit Bildern der Baumstruktur zudem noch viel besser als bei mir hier erklärt.

Die CSS Pseudo-Klass checked

Wenn wir bei CSS sind, dann greifen wir schon mal vor, auf die Pseudo-Klasse checked.

<style>
input[type=checkbox] + label {
color: red;
} 
input[type=checkbox]:checked + label {
color: green;
} 
</style>

<input type="checkbox" id="ossm" name="ossm"> 
<label for="ossm">CSS is Awesome</label>

Mit diesen coolen Zeilen können wir anhand des Status einer Checkbox die Labelfarbe ändern. Brauchen wir gleich noch.

Warum der erste Versuch Schrott ist

Der erste Versuch ist absolut unbrauchbar. Das Menu bleibt nicht mal offen, um einen Unterpunkt auswählen zu können. Das bekommt man vielleicht noch hin, aber spätestens, wenn man es dann mit einem Smartphone aufruft, harzt es. Man kann zwar noch zusätzlich zu hover active und focus nehmen. Dann bleibt auf dem Safari eines iPhones das Menü vielleicht auf, aber nicht unter Chrome auf Android. Also muss eine andere Lösung her. Ich verwenden eine Checkbox, um das Menü offen oder geschlossen zu halten. Diese Idee ist nicht neu, ich habe sie so bei Tony Thomas von Medialoot.com praktisch übernommen. In seinem Artikel erklärt er ebenfalls die Herleitung eines Drop-Down-Menüs. Da mein Menü aber anders aussehen muss, habe ich seine Strategie hier nochmal etwas "auseinandergenommen".

Zweiter Versuch

2.css

<!DOCTYPE html>
<html lang="de"> 
<head> 
<title></title> 
<meta charset="utf-8" /> 
<link rel="stylesheet" href="2.css" type="text/css" media="screen" /> 
<meta name="viewport" content="width=device-width, initial-scale=1.0"> 
</head> 
<body>
<div id="menucontainer"> 
<label for="show-menu" class="show-menu"> MENU </label> 
<input type="checkbox" id="show-menu" role="button"> 
<ul id="menu"> 
<li><a href="">Rubrik 1</a> 
<ul><li><a href="">Unterrubrik 1</a></li> 
<li><a href="">Unterrubrik 2</a></li> 
<li><a href="">Unterrubrik 3</a></li> </ul> </li> 
<li><a href="">Rubrik 2</a> 
<ul><li><a href="">Unterrubrik 1</a></li> 
<li><a href="">Unterrubrik 2</a></li>
<li><a href="">Unterrubrik 3</a></li> </ul> </li> 

<li><a href="">Rubrik 3</a> 
<ul><li><a href="">Unterrubrik 1</a></li> 
<li><a href="">Unterrubrik 2</a></li>
<li><a href="">Unterrubrik 3</a></li>
</ul></li></ul>
</div> 
<h1>Dies ist ein Powertext</h1> 
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur 
</p> 
</body>
</html>

Und auch hier das zugehörige CSS 2.css

#menu{
display: none;
}

input[type=checkbox]:checked ~ #menu{
display: block;
position: absolute;
background: white;
border: 1px solid black;
}
 

Na, erraten, was hier passiert? Mit der Pseudo-Klasse checked wird das Untermenü eingeblendet, sobald die Checkbox angeklickt ist. Das funktioniert schon mal ganz gut. Aber optisch etwas seltsam, oder?

Der Weg zum responsive Menu

Dritter Versuch

Versuchen wir es ein bisschen schöner zu machen. Dazu pumpen wir einfach das CSS noch weiter auf. Als erstes verstecken wir die Checkbox mit display:none. Dann setzen wir statt des Textes "Menü" ein auf den ersten Blick etwas seltsam anmutendes DIV-Konstrukt, was aber nichts anderes wird, als da bekannte "Hamburger-Menü".

Für die Erklärung der weiteren Anweisungen bitte die Kommentare im CSS beachten.

#menu{
display: none;
}

/* Ist die (unsichtbare) Checkbox im Zustand "checked"
lassen wir das Menu erscheinen, setzen es auf 100% Breite, 
versehen es mit weissem Hintergrund und zeichnen einen Rahmen darum
*/
input[type=checkbox]:checked ~ #menu{
display: block;
width: 100%
position: absolute;
background: white;
border: 1px solid black;
}

/* Checkox verstecken */
input[type=checkbox]{
display: none;
}

/* Wir bauen uns ein schönes Hamburger Menü */
#hamburger {
cursor: pointer;
display: block;
height: 25px;
padding: 3px 3px 3px;
position: relative;
width: 25px;
background: white;
}

/* Aus den drei div in dem #hamburger-div machen wir jetzt die Striche */
#hamburger div {
background-color: #57575e;
border: 1px solid #57575e;
border-radius: 2px 2px 2px 2px;
height: 2px;
margin-top: 3px;
width: 90%;
}


/* Hier schalten wir die Aufzählungszeichen aus, verringern den Standard-Einzug 
und 
rücken alles gleich ein. Padding auf 0 setzen und mit text-ident arbeiten, da 
bei einem 
padding > 0 die Hover-Fläche nicht über die ganze Breite geht */
#menucontainer ul, #menucontainer li{
list-style-position:inside;
list-style-type:none;
padding-left: 0;
text-indent: 10px;
}

/* Jetzt schalten wir die Unterstreichung beim Link weg*/
#menu a
{
text-decoration: none;
}

/* Hier aktivieren wir "Hover". Damit wird ein Link hellgrau hinterlegt, sobald 
die wenn Maus darüber ist*/
#menu a:hover
{
background: lightgray;
}

/* Hier schalten wir alle Links erstmal fett... */
#menu li a{
font-weight:bold;
width: 100%;
display: block;
}

/*... und hier die Links in den Unterlisten (keine Kategorien) zurück auf 
normal*/
#menu li ul li a{
font-weight:normal !important;
}

Das HTML ändert sich nur relativ geringfügig. Hier nur der Teil im div.

<div id="menucontainer">
<label for="show-menu" class="show-menu"> <div id="hamburger">
<div></div>
<div></div>
<div></div>
</div> </label>
<input type="checkbox" id="show-menu" role="button">
<ul id="menu">
<li><a href="">Rubrik 1</a>
<ul>
<li><a href="">Unterrubrik 1</a></li>
<li><a href="">Unterrubrik 2</a></li>
<li><a href="">Unterrubrik 3</a></li>
</ul>
</li>
<li><a href="">Rubrik 2</a>
<ul>
<li><a href="">Unterrubrik 1</a></li>
<li><a href="">Unterrubrik 2</a></li>
<li><a href="">Unterrubrik 3</a></li>
</ul>
</li>
<li><a href="">Rubrik 3</a>
<ul>
<li><a href="">Unterrubrik 1</a></li>
<li><a href="">Unterrubrik 2</a></li>
<li><a href="">Unterrubrik 3</a></li>
</ul>
</li>
</ul> 
</div>

Der Weg zum responsive MenuSieht schon mal gar nicht so ganz schlecht aus, oder?

Versuch 4

Schön, aber so richtig responsiv ist das Menü so nicht. Auf einem Desktop mit gängiger Breite sieht es eher etwas "doof" aus. Das Design, das ich umzusetzen habe, sieht vor, dass auf einem Desktop alle Menüpunkte in einer grossen Box nebeneinander erscheinen soll. Also müssen wir nochmal über das CSS.

Mit der @media screen-Anweisung fragen wir die Breite des Displays ab. Bei breiten Displays setzen wir die Menüs nebeneinander. Ich habe ehrlich gesagt grosse Mühe gehabt, mit den richtigen CSS-Selektoren die mehrfach verschachtelte Liste anzusprechen. Wenn man hier nicht weiterkommt, hilft es aber z.B. mit einem "border: 1px solid red" einen Rahmen zu setzen, um zu sehen, ob man im richtigen Bereich ist. Auch kann man die Seite im Browser öffnen und via rechte Maustaste und "Element untersuchen" nach den richtigen Selektoren suchen. Um nur die Hauptrubriken anpassen zu können, braucht es hier definitiv den Child-Selektor. Hier also der neue (komplette) Code.

#menu{
display: none;
}


/* Checkox verstecken */
input[type=checkbox]{
display: none;
}

/* Wir bauen uns ein schönes Hamburger Menü */
#hamburger {
cursor: pointer;
display: block;
height: 25px;
padding: 3px 3px 3px;
position: relative;
width: 25px;
background: white;
}

/* Aus den drei div in dem #hamburger-div machen wir jetzt die Striche */
#hamburger div {
background-color: #57575e;
border: 1px solid #57575e;
border-radius: 2px 2px 2px 2px;
height: 2px;
margin-top: 3px;
width: 90%;
}


/* Hier schalten wir die Aufzählungszeichen aus, verringern den Standard-Einzug 
und 
rücken alles gleich ein. Padding auf 0 setzen und mit text-ident arbeiten, da 
bei einem 
padding > 0 die Hover-Fläche nicht über die ganze Breite geht */
#menucontainer ul, #menucontainer li{
list-style-position:inside;
list-style-type:none;
padding-left: 0;
text-indent: 10px;
}

/* Jetzt schalten wir die Unterstreichung beim Link weg*/
#menu a
{
text-decoration: none;
}

/* Hier aktivieren wir "Hover". Damit wird ein Link hellgrau hinterlegt, sobald 
die wenn Maus darüber ist*/
#menu a:hover
{
background: lightgray;
}

/* Hier schalten wir alle Links erstmal fett... */
#menu li a{
font-weight:bold;
width: 100%;
display: block;
}

/*... und hier die Links in den Unterlisten (keine Kategorien) zurück auf 
normal*/
#menu li ul li a{
font-weight:normal !important;
}


/* Hier kommt etwas responsive Magic */

/*Screen-Breite > 700px */
@media screen and (min-width: 701px) {
/* Ist die (unsichtbare) Checkbox im Zustand "checked"
lassen wir das Menu erscheinen, 
versehen es mit weissem Hintergrund 
und zeichnen einen Rahmen darum
*/
input[type=checkbox]:checked ~ #menu{
display: inline-block;
position: absolute;
background: white;
border: 1px solid black;
padding-right: 10px;
padding-bottom: 5px;
} 

/* In der Desktop-Variante setzen wir die Hauptrubriken nebeneinander */
ul#menu>li 
{
display: table-cell;
}
}

/*Screen-Breite <= 700px */
@media screen and (max-width: 700px) {
/* Ist die (unsichtbare) Checkbox im Zustand "checked"
lassen wir das Menu erscheinen, 
versehen es mit weissem Hintergrund
und zeichnen einen Rahmen darum
*/
input[type=checkbox]:checked ~ #menu{
display: block;
width: auto;
position: absolute;
background: white;
border: 1px solid black;
padding-right: 10px;
padding-bottom: 5px;
}

}

Das Ergebnis hat optisch sicher noch viele Mängel, aber wenn der Weg bis hier klar ist, sollte es mit genügend CSS-Kenntnissen auch hin zum perfekt gestylten responsive Menü kein Problem mehr sein. Wichtig ist hierbei die Kenntnis der oben erklärten Kombinatoren.

Der Weg zum responsive Menu
So sieht der 4. Versuch auf einem Desktop aus

Der Weg zum responsive Menu
So sieht der 4. Versuch auf dem Smartphone aus
Du willst meine Arbeit unterstützen? Dann freue ich mich über eine kleine Spende!

Kommentar hinterlassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert