Zur Navigation

Zwei Navis (desktop-first), die mobile per Toggle-Klickbutton aus-/einklappen sollen

1 Martin

Hallo,
ich bin dabei, meine alten WP-Sites auf reines HTML und CSS umzustellen, mit einem dreispaltigen Grid. Ich nutze Visual Studio Code.

Desktop-first ist soweit alles erledigt, HTML und CSS. Im letzten Schritt geht es jetzt darum, die Site responsiv zu machen. Problem sind da die beiden Navs, die mit JavaScript funktionieren sollen, ich kann das aber nicht und außer für die Navs brauche ich es auch nicht.

Die Seiten haben eine horizontale und eine vertikale Nav (ohne Dropdown-Untermenü), die für mobile-Geräte (media query) als zwei aus/einklappbare HTML-Buttons erscheinen sollen.

Das Aus/Einklappen soll mit einem Klickevent durch Javascript und aria-expanded passieren.

Leider habe ich von JS keine Ahnung. Zwei Beispiele im Web kommen meiner Nav zwar nahe (HTML-Button, aria-expanded, desktop-first), aber die Codes unterscheiden sich.


Der HTML-Code der ersten Nav und das nötige CSS sieht wie folgt aus und sollte soweit passen (die zweite Nav hat den "gleichen" HTML-Code, nur andere Klassennamen). Die Anpassung der Stylings mache ich dann hinterher.

Kann man das hier im Forum besprechen oder ist das zu kompliziert?

<nav class="headnav" aria-label="label1">
  <button class="headnav-button" aria-expanded="false" type="button">Menü 1<span class="button-pfeil">&#x25bc;</span></button>
  <ul class="headnav-haupt-ul">
    <li><a href="url1">Linktext1</a></li>
    <li><a href="url2">Linktext2</a></li>
    <li><a href="url3">Linktext3</a></li>
    <li><a href="url4">Linktext2</a></li>
    <li><a href="url5">Linktext5</a></li>
    <li><a href="url6">Linktext6</a></li>
  </ul>
</nav>


CSS :

button.headnav-button {
    display: none; 
    padding-top: 5px;
    padding-bottom: 5px;
    padding-right: 15px;
    padding-left: 15px;
    font-family: Arial;
    font-size: 1rem;
    background-color:#fffbf1; /*  */
    order: 2px solid #000000; /*  */
}

button.headnav-button > span.button-pfeil {
    margin-left: 10px;
}

/* responsiver Code, media query */
@media screen and (max-width: 600px) {
div.grid-container { 
  display: grid;
  max-width: 600px; 
  grid-template-columns: 1fr 1fr; 
  grid-template-rows: auto auto; 
  grid-template-areas: 
    "header header"
    "headnav sidenav"
    "main main"
    "aside aside"
    "footer footer"; 
  background-color: #ffffff; 
  margin-left: auto; 
  margin-right: auto; 
  padding: 9px; 
  border: 1px solid black; 
  margin-top: 3px; 
  margin-bottom: 3px; 
  border-radius: 6px;
}

/* responsiver Code, Button eingeblendet */
button.headnav-button, button.sidenav-button {
  display: block;
}

/* responsiver Code, ul ausgeblendet */
ul.headnav-haupt-ul, ul.sidenav-ul {
  display: none;
}

13.09.2025 11:37

2 Jörg Kruse

Ein Beispiel war vermutlich das hier:

https://jamesevers.co.uk/articles/creating-an-accessible-navigation-menu-and-toggle-with-vanilla-javascript

Du kannst das Script für deine Navigation verwenden, indem du die Selektoren an dein HTML anpasst:

const navToggle = document.querySelector('.headnav-button');
const navList = document.querySelector('.headnav-haupt-ul');
const navLinks = document.querySelectorAll('.headnav-haupt-ul li a');

13.09.2025 15:19

1 Forenmitglied fand diesen Beitrag gut

3 Martin

Das wäre ja super, wenn es so einfach wäre. Das Beispiel ist recht überschaubar.

Über dein Beispiel bin ich auch gestolpert, habe es aber nicht weiter verfolgt, wegen folgendem Satz:
"In essence it uses a hidden attribute on the nav element to determine its visible state, and that is controlled via a click event on a button."

Das hat mich irritiert. Der "übliche" und korrekte Weg, den ich auch so gewählt habe, ist wohl der, dass
- der Button desktop-first ausgeblendet wird,
- der Button mobile eingeblendet wird und das ul default ausgeblendet.

In seinem HTML sehe ich ein "hidden"-Attr. beim ul, nicht bei nav, wie er sagt. Nav scheint aber auch niemand sonst zu verwenden dafür. Alle blenden das ul aus und nehmen zum Verstecken/Ausblenden immer display: none, das am sichersten zu sein scheint.
Ansonsten scheint er gar nichts ein/auszublenden in seinem CSS? Weil mobile-first? Ich sehe auch gar kein MQ.

Die zwei Beispiele, die ich meinte, sind komplexer.

Das eine hat zusätzlich ein Logo und ein Suchfeld, was ich beides nicht brauche. Und es hat zusätzlich zwei DD-Untermenüs, die ebnfalls DD/Toggle-Buttons haben. Das wäre dann wie bei meiner anderen Site, die ich auch noch umstellen muss. Aber die jetzige hat keine Untermenüs:
https://www.freecodecamp.org/news/how-to-build-a-responsive-navigation-bar-with-dropdown-menu-using-javascript/

Das andere Beispiel hat keinen HTML-, sondern einen div-Button und obwohl das JS mit aria-expanded arbeitet, sehe ich keines beim div-Button im HTML!? Ansonsten erklärt es die Sachen recht ausführlich und wäre mein Fall (nur das Logo brauche ich nicht):
https://thesyntaxdiaries.com/responsive-navbar-html-css-js

Sehe ich es richtig, dass ich für meine zwei Navs zwei JavaScripts brauche (jedes mit ein paar Blöcken JS-Code) und man nicht in einem Code beide Navs gleichzeitig behandeln darf/kann/soll?

13.09.2025 18:54

4 Jörg Kruse

Nur kurz zu ein paar Fragen, da ich gleich ins Wochenedne gehe :) - die beiden komplexeren Beispiel schaue ich mir nach dem Wochenende genauer an (falls da noch Bedarf ist)

In seinem HTML sehe ich ein "hidden"-Attr. beim ul, nicht bei nav, wie er sagt. Nav scheint aber auch niemand sonst zu verwenden dafür.

Ja, weil dort der Toggle-Button innerhalb von nav liegt. Der Button soll ja sichtbar sein, wenn das Menü ausgeblendet ist.

Ansonsten scheint er gar nichts ein/auszublenden in seinem CSS? Weil mobile-first? Ich sehe auch gar kein MQ.

Du kannst in einer Media Query das Attribut hidden mit display:block in der Desktop-Ansicht überschreiben, z. B.:

@media only screen and (min-width: 768px) {
  .headnav-haupt-ul {
    display:block;
  }
  .headnav-button {
    display:none;
  }
}

Sehe ich es richtig, dass ich für meine zwei Navs zwei JavaScripts brauche (jedes mit ein paar Blöcken JS-Code) und man nicht in einem Code beide Navs gleichzeitig behandeln darf/kann/soll?

Jain, du benötigst nur ein JavaScript, aber der Ablauf muss zweifach mit unterscheidbaren Variablen erfolgen. Wenn ein Script für ein Menü taugt, könnte man dieses für zwei Menüs in einer Schleife laufen lassen. Beispiel für das von mir verlinkte Script und zwei Navigationen 'headnav' und 'sidenav':

const navToggle[0] = document.querySelector('.headnav-button');
const navList[0] = document.querySelector('.headnav-haupt-ul');
const navLinks[0] = document.querySelectorAll('.headnav-haupt-ul li a');

const navToggle[1] = document.querySelector('.sidenav-button');
const navList[1] = document.querySelector('.sidenav-haupt-ul');
const navLinks[1] = document.querySelectorAll('.sidenav-haupt-ul li a');

for (let i = 0; i <= 1; i++) {
    navToggle[i].addEventListener('click', function () {
        if (navList[i].hasAttribute('hidden')) {
            this.setAttribute('aria-expanded', 'true');
            navList[i].removeAttribute('hidden');
            navLinks[i][0].focus();
        } else {
            navList[i].setAttribute('hidden', 'true');
            this.setAttribute('aria-expanded', 'false');
        }
    });
}

document.addEventListener('keydown', (event) => {
    if (event.isComposing || event.keyCode === 229) {
        return;
    }
    if (event.keyCode === 27) {
        for (let i = 0; i <= 1; i++) {
            if (!navList[i].hasAttribute('hidden')) {
                navToggle[i].setAttribute('aria-expanded', 'false');
                navList[i].setAttribute('hidden', 'true');
            }
        }
    }
});

13.09.2025 20:49 | geändert: 13.09.2025 21:09

5 Martin

Danke schon mal.

Na, dann genieß den Sonntag... :)

Ansonsten scheint er gar nichts ein/auszublenden in seinem CSS? Weil mobile-first? Ich sehe auch gar kein MQ.


Du kannst in einer Media Query das Attribut hidden mit display:block in der Desktop-Ansicht überschreiben, z. B.:

@media only screen and (min-width: 768px) {
.headnav-haupt-ul {
display:block;
}
.headnav-button {
display:none;
}
}

Ich habe das mit dem Ein/Ausblenden vom Button und dem ul bereits gemacht, siehe CSS-Code im Eröffnungspost. Das passt auch soweit.

Ich war nur von dem Beispiel insofern irritiert, als es mit dem hidden eine andere Methode verwendet und das Beispiel offenbar von einem mobile-first-Ansatz ausgeht, ohne dann aber ein entspr. MQ zu ergänzen.
Mein Ansatz ist desktop-first, nicht mobile-first.

Je ähnlicher, desto besser. Jeder Unterschied macht es im Zweifelsfall für mich schwieriger und wirft früher oder später vermutlich weitere Fragen auf.

Ich würde eher zu dem Beispiel von freecodecamp tendieren. Man müsste sich da halt das für mich überflüssige Logo und das Suchfeld sowie die zwei Dropdown-Untermenüs wegdenken.
Wobei ich letzteres bei der Umstellung der nächsten beiden Websites brauche, die ebenfalls ein/zwei DD-Untermenüs haben. Vielleicht könnte man das jetzt schon mitnehmen und auskommentieren, so wie im CSS das oft geschieht? Ist nur eine Idee.

Jain, du benötigst nur ein JavaScript, aber der Ablauf muss zweifach mit unterscheidbaren Variablen erfolgen. Wenn ein Script für ein Menü taugt, könnte man dieses für zwei Menüs in einer Schleife laufen lassen. Beispiel für das von mir verlinkte Script und zwei Navigationen 'headnav' und 'sidenav':

Ich weiß nicht, ob es überhaupt ginge, aber wenn es sauber getrennt mit zwei JS-Codes (einer für jede Nav) einfacher und überschaubarer wird für mich, dann wäre es mir im Zweifelsfall recht. Etwas mehr Code wäre es mir wert.
Wenn z.B. mal an einer Nav etwas sich ändert, kann ich sicher sein, dass es die andere responsiv nicht tangiert.

Als Hobby-Webmaster, der nach Monaten oft nicht mehr genau weiß, warum welche Codes was genau machen und dann nachschauen muss (aber auch kann), bin ich mit eher einfachen, gut kommentierten und für mich verständlichen Lösungen bisher gut gefahren.

14.09.2025 16:22

6 Jörg Kruse

Ich war nur von dem Beispiel insofern irritiert, als es mit dem hidden eine andere Methode verwendet und das Beispiel offenbar von einem mobile-first-Ansatz ausgeht, ohne dann aber ein entspr. MQ zu ergänzen.

Das Beispiel geht nicht von mobile-first aus. Es wird nur ein einfaches JavaScript an ein bestehendes Menü drangeflanscht, ohne dass am CSS oder HTML großartig etwas geändert werden muss - lediglich das hidden Attribut muss eingefügt werden. Und die Frage der Responsivität wird (wie auch sonst) unabhängig von dem JavaScript gelöst. Letzteres kümmert sich lediglich um den Toggle-Effekt! genau deswegen ist es für nicht verschachtelte Menüs sehr leicht umzusetzen.

Für das verschachtelte Menü eignet sich dann wohl das Beispiel auf freecodecamp.org besser, ist aber auch schwieriger anzupassen.

Ich weiß nicht, ob es überhaupt ginge, aber wenn es sauber getrennt mit zwei JS-Codes (einer für jede Nav) einfacher und überschaubarer wird für mich, dann wäre es mir im Zweifelsfall recht.

Mit einem Duplizieren des JavaScript-Codes ist es nicht getan. Im Falle des Codes von freeCodeCamp müssen dann nicht nur duplizierte Konstanten umbenannt werden, sondern auch duplizierte Funktionen. Damit weicht man schon erheblich ab von Best Practices wie dem für Programmierung sehr grundsätzlichen DRY-Prinzip. Du kannst vesuchen, als Hobby-Webmaster diesen Weg der Duplizierung zu gehen. Das ist aber eine Sackgasse, in die dir erfahrenere Programmierer nicht freudig folgen werden, um beim Debuggen oder Erweitern des Codes zu helfen.

Ich schlage vor, dass du das Beispiel in einem ersten Schritt (testweise) für ein erstes Menü implementierst. Wenn das funktioniert, kann ich dich dabei unterstützen, das JavaScript für das zweite Menü zu erweitern.

15.09.2025 16:15

7 Martin

Ich schlage vor, dass du das Beispiel in einem ersten Schritt (testweise) für ein erstes Menü implementierst. Wenn das funktioniert, kann ich dich dabei unterstützen, das JavaScript für das zweite Menü zu erweitern.

Das ist vernünftig.

Zu dem James-Beispiel habe ich zwei Fragen:
- const definiert offenbar bestimmte Variablen, mit denen dann die folgende Funktion irgendwas macht. Abgesehen von extra Untermenüs wie bei freecode sind es bei allen Beispielen, die ich gefunden habe immer zwei const-Werte, nämlich button und ul.
Warum braucht James auch noch die ul-Links, zumal "navLinks" im JS dann auch gar nicht mehr auftaucht?

- Macht das James-Beispiel nur Sinn, wenn wir das hidden-Attribut im ul übernehmen oder können wir das so machen, wie ich es im Eröffnungspost als derzeitiger Status quo bei mir gemacht habe (default ist im CSS Button ausgeblendet, im MQ wird dann Button ein- und das ul ausgeblendet)?

Wenn ich den Code einfach nur in meine JS-Datei kopiere, wird übrigend keycode als deprecated durchgestrichen.

Neben "ESC" gibt es noch zwei weitere Close-Fälle, kann das sein?

15.09.2025 19:33

8 Jörg Kruse

- const definiert offenbar bestimmte Variablen, mit denen dann die folgende Funktion irgendwas macht.

Mit const werden nicht Variablen, deren Werte variabel = veränderbar sind, definiert, sondern Kontanten, deren Werte nach der Zuweisung unveränderlich sind. Diese Konstanten werden dann in den Funktionen benötigt, ja.

Warum braucht James auch noch die ul-Links, zumal "navLinks" im JS dann auch gar nicht mehr auftaucht?

An einer Stelle wird navLinks verwendet:

        // Set focus on first link
        // will be highlighted for keyboard users
        navLinks[0].focus();

Nsch dem Öffen des Menüs wird der Fokus (für Anwender, die mit der Tastatur navigieren) auf den ersten Menüeintrag gesetzt.

- Macht das James-Beispiel nur Sinn, wenn wir das hidden-Attribut im ul übernehmen oder können wir das so machen, wie ich es im Eröffnungspost als derzeitiger Status quo bei mir gemacht habe (default ist im CSS Button ausgeblendet, im MQ wird dann Button ein- und das ul ausgeblendet)?

Das Beispiel setzt das hidden Attribut voraus. "display: block" überschreibt zwar das hidden Attribut, aber "display: none" wird vom Browser nicht als hidden Attribut interpretiert.

Wenn ich den Code einfach nur in meine JS-Datei kopiere, wird übrigend keycode als deprecated durchgestrichen.

Ja, zukunftssicher wäre event.key oder event.code. Also z. B. "event.code === 'Backquote'" bzw. "event.key === 'Escape'"

Neben "ESC" gibt es noch zwei weitere Close-Fälle, kann das sein?

Fällt mir grad nichts zu ein, kann man aber ja ggf. ergänzen.

16.09.2025 11:03

9 Martin

Ich tu mich ehrlich gesagt mit dem James-Bsp. schwer. Es scheint nicht für mich gemacht zu sein.

Nicht nur wegen dem hidden-Attr. im ul und der gängigeren Alternative, die ich mühsam schließlich verstanden und umgesetzt habe.

Es macht mit JS (per zusätzlichem const) einen focus, den ich ohne JS für alle Buttons und Links ect. an einer Stelle im CSS regle. Es löst irgendein "IME-Composition"-Problem, von dem ich bei allen anderen Beispielen noch nie gehört habe. Es geht auf einen Close-Grund ein (ESC), ich brauche aber alle insgesamt drei (normales Button-Toggle, ESC, Menülink anklicken).
Es hat keine DD-Untermenüs, die im 2. oder 3. Schritt für mich noch mal relevant werden (spät. bei der nächsten Site). Und dass es keinen klaren Bezug zu mobile-first oder desktop-first hat und deprecated Dinge verwendet, macht es auch nicht besser.

Klar kann man alles ergänzen, korrigieren, weglassen und erklärend kommentieren, aber für einen Hobby-Webmaster und "Quartalsarbeiter" wie mich ist das eine unnötige Erschwernis. Wenn ich in einem halben Jahr oder Jahr an den Menüs irgendwas machen muss/will und dieses Beispiel als mein Basis-und Bezugsbeispiel anschaue, dann bin ich wahrscheinlich mehr verwirrt, als wie wenn ich wieder von vorne anfange.

Machen wir es doch so: Ich bastle mit den sehr ähnlichen Beispielen, die ich gefunden habe, erst mal den JS-Code für eine Nav ohne DD-Untermenü zusammen. Und stelle ihn dann hier rein.

Dann musst du nur drüberschauen und sagen, was falsch oder suboptimal ist und ich habe mich zumindest ein wenig mit JS auseinandergesetzt und eine vage Vorstellung davon, was welcher Teil macht.

16.09.2025 23:31 | geändert: 16.09.2025 23:34

10 Jörg Kruse

Ich tu mich ehrlich gesagt mit dem James-Bsp. schwer. Es scheint nicht für mich gemacht zu sein.

Ich hatte dies auch nur als Beispiel herausgesucht, da du in deinem ersten Post deine Favoriten noch nicht verlinkt hattest, um daran zu demonstrieren, wie ein solches Script angebunden und auf zwei Menüs erweitert werden kann. Vom Prinzip lässt sich das ja auf andere Beispiele übertragen.

Machen wir es doch so: Ich bastle mit den sehr ähnlichen Beispielen, die ich gefunden habe, erst mal den JS-Code für eine Nav ohne DD-Untermenü zusammen. Und stelle ihn dann hier rein.

Dann musst du nur drüberschauen und sagen, was falsch oder suboptimal ist und ich habe mich zumindest ein wenig mit JS auseinandergesetzt und eine vage Vorstellung davon, was welcher Teil macht.

Ja, das können wir so machen.

17.09.2025 15:18