Navigation Bar, div anzeigen beim klicken auf einen Link
ArneS
- navigation & menu
Hallo, Ich würde auf meiner Seite gerne eine art Navigationsleiste einfügen dabei soll beim klicken auf den ersten Link ein div angezeigt werden (der eine reihe von Bildern enthält). Klickt man auf den Zweiten Link wird der div mit einem anderen ersetzt (der andere Bilder enthält). So kann man auswählen welche Bilder man angezeigt bekommt.
Mir ist bisher noch keine Lösung dafür eingefallen und hoffe das mir hier jemand weiterhelfen kann. Wäre Natürlich super wenn das ganze ohne JavaScript umsetzbar wäre aber wenn es nicht anders geht dann muss ich mich halt damit noch ein bisschen beschäftigen.
LG Arne
Hallo, Ich würde auf meiner Seite gerne eine art Navigationsleiste einfügen dabei soll beim klicken auf den ersten Link ein div angezeigt werden (der eine reihe von Bildern enthält). Klickt man auf den Zweiten Link wird der div mit einem anderen ersetzt (der andere Bilder enthält). So kann man auswählen welche Bilder man angezeigt bekommt.
Mir ist bisher noch keine Lösung dafür eingefallen und hoffe das mir hier jemand weiterhelfen kann. Wäre Natürlich super wenn das ganze ohne JavaScript umsetzbar wäre aber wenn es nicht anders geht dann muss ich mich halt damit noch ein bisschen beschäftigen.
Hallo,
Dein Begehren ist ein typischer Anwendungsfall für die HTML-Elemente details und summary. Das Ergebnis nennt man landläufig Akkordeon.
Siehe hier: https://wiki.selfhtml.org/wiki/HTML/Interaktiv/details
Ganz ohne Javascript, nur mit HTML und CSS!
habe das mal ausprobiert und Ansicht funktioniert das ziemlich gut. Vielen dank dafür erstmal. Jetzt habe ich nur noch ein Problem undzwar hätte ich gerne das man nur einen "detail Bereich" gleichzeitig ausklappen kann. Also dass sich quasi der aktuell geöffnete Bereich schließt wenn man auf ein anderes Summary klickt. Geht das?
Servus!
habe das mal ausprobiert und Ansicht funktioniert das ziemlich gut. Vielen dank dafür erstmal.
Super, vielen Dank an @meltemi für den Link!
Jetzt habe ich nur noch ein Problem undzwar hätte ich gerne das man nur einen "detail Bereich" gleichzeitig ausklappen kann. Also dass sich quasi der aktuell geöffnete Bereich schließt wenn man auf ein anderes Summary klickt. Geht das?
Ja, aber so eine Interaktion benötigt JavaScript. Das scheint anfangs eine ziemliche Hürde, ist aber oft einfacher.
Ich hatte hier mal angefangen, habe aber grade gar keine Zeit dies fertigzustellen:
Bei einem Klick würdest du dein aktuelles details öffnen und mit JavaScript eine Funktion aufrufen, die …
Es wäre super, wenn sich irgendjemand dieses Themas annehmen könnte!
Herzliche Grüße
Matthias Scharwies
@@meltemi
Dein Begehren ist ein typischer Anwendungsfall für die HTML-Elemente details und summary. Das Ergebnis nennt man landläufig Akkordeon.
Nö. details
ist kein Akkordeon.
😷 LLAP
Servus!
Das Ergebnis nennt man landläufig Akkordeon.
Ich glaube, dass das landläufig das schon gut anspricht.
Der Artikel beschreibt imho nur die Probleme innerhalb eines details-Elements Überschriften wie h1 zu verwenden, da in diesem Falle die Zugänglichkeit nicht gewährt wäre.
Herzliche Grüße
Matthias Scharwies
Hallo Gunnar,
ich habe diverse dieser Artikel gelesen, die sich damit beschäftigen, wofür details/summary nicht geignet bist, und ich habe sie nicht verstanden. Dieses Elementpaar ist dafür gemacht, Inhalte ein- und auszublenden. Statt dessen werden „bewährte“ Lösungen vorgeschlgen, bei denen mit einigem an Javascript und Aria-Attributen andere Elemente für diese Aufgabe zurechtgebogen werden.
Gruß
Jürgen
Servus!
@Matthias Apsel hat die Lösung gefunden, die Höhen des details-Elements mithilfe von getBoundingClientRect auszulesen und so zu animieren:
JavaScript/Tutorials/Akkordeon_mit_details#weicher Übergang
Ich versuche mich jetzt an einem "Tabbed Register" mit details. Die summary-Elemente sind auch ohne tabindex mit der Tab-Taste antabbar; ist eine Navigation mit Pfeil-vor und -Zurück aus Euren Sicht noch nötig?
Herzliche Grüße
Matthias Scharwies
Hallo Matthias,
Ich versuche mich jetzt an einem "Tabbed Register" mit details. Die summary-Elemente sind auch ohne tabindex mit der Tab-Taste antabbar; ist eine Navigation mit Pfeil-vor und -Zurück aus Euren Sicht noch nötig?
ich habe die Pfeilnavigation bisher nie ausprobiert und auch nie vermisst. Mir reicht TAB und Shift TAB aus.
Bei Assistiven Techniken wüsste ich auch garnicht, welchen Sinn ich rauf-runter-links-rechts geben sollte.
Gruß
Jürgen
Servus!
Hallo Matthias,
Ich versuche mich jetzt an einem "Tabbed Register" mit details. Die summary-Elemente sind auch ohne tabindex mit der Tab-Taste antabbar; ist eine Navigation mit Pfeil-vor und -Zurück aus Euren Sicht noch nötig?
ich habe die Pfeilnavigation bisher nie ausprobiert und auch nie vermisst. Mir reicht TAB und Shift TAB aus.
Danke, finde ich auch! Ich lasse das alte Bsp mit divs und einer Liste mit aria-labels und Pfeilsteuerung aber drunter stehen - nur zum Vergleich.
Gruß
Jürgen
Herzliche Grüße
Matthias Scharwies
Hallo ArneS,
es gibt Möglichkeiten, sowas ohne JavaScript umzusetzen, aber sie sind nicht gut.
Eine einfache Möglichkeit ist das von meltemi verlinkte <details> Element, aber das verhält sich nicht ganz so, wie Du Dir das vorstellst, weil die Aufklappbereiche sich nicht überlagern.
Das, was Du möchtest, geht ohne JavaScript nur durch Einsatz des so genannten "Checkbox Hack" - oder in deinem Fall: Radiobutton-Hack. Aber: das macht die Seite nicht mehr bedienbar (im Sinne von: für jeden bedienbar), weshalb diese Technik nicht willkommen ist.
Ich würde Dir zwei Alternativen empfehlen:
Mach mehrere HTML Seiten, jede für eine Bildersicht, und wechsle mit Links zwischen diesen Seiten. Dann hast Du auch gleich eine vor-/rück-Navigation für die letzte Ansicht. Ist natürlich nicht so schick.
Verwende Buttons statt Links und benutze JavaScript, um abhängig vom geklickten Button eine bestimmte Liste von Bildern einzublenden. Außer JavaScript brauchst Du dann auch aria-Attribute, damit ein Assistenztechniknutzer weiß, welche Steuerung was auslöst. Wobei - eine Bildergalerie ist für Screenreader vermutlich nicht so das Traumszenario...
Rolf
Vielen Dank für die ausführliche Antwort, ich habe das mit dem Detail Element mal ausprobiert und an sich hat das erstmal sehr gut Funktioniert. Das einzige Problem das ich habe ist das man ja mehrere Details gleichzeitig aufmachen kann und es bei mir ideal wäre wenn sich der gerade offene Bereich einklappt sobald man einen anderen aufmacht.
Ich suche jetzt mal nach einer Lösung für das Problem und schau ob auch sonst alles so Funktioniert wie ich es mir vorstelle. Wenn ich noch andere Probleme Finde dann werde ich mal eine von deinen Lösungen ausprobieren, Vielen Dank.
nochmal Hallo,
zum von Rolf B erwähnten "Checkbox Hack" oder "Radiobutton Hack" gab's hier früher mal eine Anleitung, die aber leider gelöscht wurde (vermutlich wegen mangelnder Zugänglichkeit).
Guck' mal hier: genau was Du brauchst (ein Bereich geöffnet, die anderen geschlossen), aber eben nicht zugänglich (also nicht vollständig mit der Tastatur bedienbar): https://www.mediaevent.de/tutorial/css-accordeon.html
Oder Du suchst in der Suchmaschine Deiner Wahl nach >akkordeon checkbox hack< .
P.S. Falls sich hier irgendein Korinthenka[zensiert]er über die verwendeten falschen Anführungszeichen aufregt: das ginge mir am A[zensiert] vorbei.
Das hört sich gut an, dann werde ich das mal ausprobieren! Vielen vielen Dank für die schnelle Hilfe. LG Arne
@@ArneS
Das hört sich gut an,
Nein. Rolf sagte, warum nicht. Und das auch schon, bevor meltemi mit der Nicht-Lösung ankam.
dann werde ich das mal ausprobieren!
Lass es.
😷 LLAP
Hallo meltemi,
ich habe den Radiobutton Hack absichtlich nicht beschrieben. Den Grund nennst Du selbst: Zugänglichkeit. Was Du vorschlägst, ist keine Lösung. Es ist die Ausgrenzung von Anwendergruppen. Bedienbare Widgets mit einem Verhalten, das dem Browser nicht eingebaut ist, benötigen eigentlich immer JavaScript.
Über den semantisch falschen Gebrauch von Eingabeelementen will ich nicht reden, das kann man sehen wie man will.
Ob man den Radiohack zugänglich machen kann, indem man mittels JavaScript einen Schwarm von Aria-Attributen verwaltet, weiß ich nicht. Aber wenn man schon in die JS Kiste greift, dann braucht man auch den Radiohack nicht mehr.
Es ist aber auch von "Normalbenutzern" nicht unbedingt gut bedienbar. Denn: Radiobuttons ändern ihren Wert sofort. Ich kann nicht mit den Pfeiltasten links/rechts laufen und dann den Abschnitt wählen, den ich möche. Ich muss statt dessen nach jedem Tastendruck warten, bis Bilder geladen wurden, die ich gar nicht haben wollte.
Natürlich ist es Arnes Entscheidung, ob er sich auf Kosten bestimmter Anwenderkreise das Leben leichter machen möchte. Es sei denn, die Seite unterliegt bestimmten Vorschriften für Bedienbarkeit. Dann geht das nicht.
Rolf
@@Rolf B
Ob man den Radiohack zugänglich machen kann, indem man mittels JavaScript einen Schwarm von Aria-Attributen verwaltet, weiß ich nicht.
😷 LLAP
@@ArneS
ich habe das mit dem Detail Element mal ausprobiert und an sich hat das erstmal sehr gut Funktioniert. Das einzige Problem das ich habe ist das man ja mehrere Details gleichzeitig aufmachen kann und es bei mir ideal wäre wenn sich der gerade offene Bereich einklappt sobald man einen anderen aufmacht.
Das könnte man mit JavaScript machen.
Zuerst dachte ich, aufs toggle
-Event zu lauschen und alle anderen details
-Elemente per ….open = false
zu schließen. Problem daran: dabei feuern wieder toggle
-Events, sodass die Dinger endlos auf- und zugehen.
Was nicht heißen soll, dass man details
-Elemente so verbiegen sollte. Oder überhaupt für ein Akkordeon einsetzen sollte.
😷 LLAP
PS: TIL, dass Firefox :focus-visible
nicht auf details
-Elemente anwendet. 😞
Hallo Gunnar,
Problem daran: dabei feuern wieder toggle-Events, sodass die Dinger endlos auf- und zugehen.
Du magst das CSS Genie sein, aber in Algorithmik kann ich Dir noch was zeigen 😉. Welcher Vollpfosten hat eigentlich in der Spec vergessen hinzuschreiben, dass das toggle Event mit bubbles=true erzeugt ewrden sollte? Oder war das etwa sinistre Absicht?
(Edit: Und bezüglich Code Quality muss ich noch eine Menge lernen)
<div class="detailsGroup">
<details>...</details>
<details>...</details>
<details>...</details>
<details>...</details>
<details>...</details>
</div>
(Edit: class statt id)
document.querySelectorAll(".detailsGroup details")
.forEach(d => d.addEventListener("toggle", detailsToggler));
function detailsToggler(ev) {
if (!ev.target.open) return;
let container = ev.target.closest(".detailsGroup");
for (let d of container.querySelectorAll("details")) {
if (d != ev.target)
d.open = false;
}
}
(Edit: querySelectorAll auf closest(".detailsGroup") anwenden, nicht auf document)
Rolf
Wow vielen vielen dank ich war schon ganz verwirrt von den ganzen Vorschlägen, ich muss leider zugeben dass meine JavaScript Kenntnisse gegen 0 gehen und ich auch nur im groben verstehe was dein Code macht. Aber ich habe ihn mal bei mir eingefügt und angepasst und er funktioniert super.
Jetzt hoffe ich mal dass das die richtige Lösung war...
LG Arne
Hallo ArneS,
wenn Du mit einer Akkordeon-ähnlichen Lösung zufrieden bist, dann ist es ja gut.
Mein Code war ziemlich komprimiert und eher für Gunnars Niveau gedacht. Und leider sind ein paar Bugs drin, deshalb bitte ich Dich, Dir das hier - bzw. das alte Posting - nochmal anzuschauen. Ich hab's im alten Posting korrigiert.
document.querySelectorAll(".detailsGroup details")
.forEach(d => d.addEventListener("toggle", detailsToggler));
Hier passiert schon eine ganze Menge.
document.querySelectorAll("...")
- diese DOM Methode durchsucht den Knoten, auf dem sie aufgerufen wird, nach Elementen, die zum angegebenen CSS Selektor passen. In diesem Fall das ganze Dokument, und sie sucht <details>
Elemente, die ein Element mit class="detailsGroup"
als Elternelement unter ihren Vorfahren haben.
CSS: class selector (Klassenselektor) und element selector (Typselektor), und descendant combinator (Nachfahrenkombinator)
Das Ergebnis von querySelectorAll ist eine NodeList. Die neueren Browser kennen ein paar NodeList-Methoden mehr als unser Wiki; im Internet Explorer würde der forEach Aufruf ohne einen Polyfill nicht funktionieren.
Aber in Chrome, Edge, Firefox und Safari schon, und forEach ruft die Funktion, die da in den Klammern steht, für jeden Eintrag in der NodeList - also für jedes gefundene details-Element, einmal auf.
d => ...
ist eine Pfeilfunktion und eine Kurzschreibweise für function(d) { return ... }
. Es gibt ein paar wichtige Feinheiten, dazu kannst Du dem Link folgen. Was hier passiert ist: Für jedes details
-Element wird addEventListener
aufgerufen, um für das toggle
-Event die Funktion detailsToggler
als Eventhandler zu registrieren.
function detailsToggler(ev) {
if (!ev.target.open) return;
for (let d of document.querySelectorAll("details")) {
if (d != ev.target)
d.open = false;
}
}
Was diese Funktion tut, ist einfacher. Und leider nicht ganz richtig.
Der Eventhandler für toggle
wird aufgerufen, wenn der "geöffnet" Zustand des details
Elements umschaltet. Von open nach close, oder von close nach open. Wir möchten dann etwas tun, wenn wir vom Öffnen eines Elements erfahren - andernfalls würden wir, wie von Gunnar beschrieben, in einer Endlosschleife landen.
Ein Eventhandler, der mit addEventListener registriert wurde, bekommt ein Event-Objekt als Parameter übergeben. Die target
Eigenschaft dieses Objekts ist das DOM Element, für das das Event ausgelöst wurde. Also unser details
Element.
Auf diesem Element wird die open
Eigenschaft geprüft. Das ist eine spezielle Eigenschaft des HTMLDetailsElement
-Objekts, mit dem <details>
im DOM dargestellt wird. Nur, wenn das Element offen ist, dann wurde es gerade geöffnet, und wir können die anderen Elemente schließen. Für dieses Schließen wird es ebenfalls ein toggle
Event geben, aber darauf reagieren wir wegen dieser Prüfung dann nicht.
Die Funktion sucht sich nun alle <details>
Elemente zusammen - und das ist ein Bug, bzw. ein Relikt einer älteren Fassung. Das Script sucht ja nur alle <details> Elemente innerhalb eines class="detailsGroup"
Containers. Davon könnte es auch mehrere geben, aber das Schließen anderer <details>
darf sinnvollerweise nur innerhalb des gleichen Containers erfolgen.
function detailsToggler(ev) {
if (!ev.target.open) return;
let container = ev.target.closest(".detailsGroup");
for (let d of container.querySelectorAll("details")) {
if (d != ev.target)
d.open = false;
}
}
Und dabei fällt dann gleich ein zweiter Bug auf:
<div id="detailsGroup">...</div>
Das muss natürlich
<div class="detailsGroup">...</div>
sein, sonst könnte man ja nicht mehrere davon verwenden. Und die programmierten Selektoren setzen eh schon Klassen voraus. Ein Wunder, dass es vorher irgendwie geklappt hat. Ich habe mir ein T-Shirt verdient.
Nach der Korrektur *räusper* ist es jedenfalls so, dass mittels der closest
Methode das nächstliegende Elternelement gesucht wird, auf das der angegebene CSS Selektor zutrifft. Das ist das <div class="detailsGroup">
. Und darauf wird wiederum mit querySelectorAll die NodeList der enthaltenen <details>
Elemente ermittelt.
Diese wird nun mit der for...of
-Schleife durchlaufen. Das ist ähnlich zu .forEach, und ich hätte for...of
auch beim Registrieren der Events verwenden können. Ich habe an dieser Stelle kein .forEach
verwendet, weil da mehr als nur ein einziger Funktionsaufruf passiert.
Ich muss nämlich prüfen, ob das gefundene <details>
Element mit dem Event-Target übereinstimmt. Nur, wenn das nicht der Fall ist, darf ich es schließen. Andernfalls machte ich mein frisch geöffnetes <details>
gleich wieder zu.
Alles klar?
Rolf
Lieber Rolf,
document.querySelectorAll("...")
- diese DOM Methode durchsucht den Knoten, auf dem sie aufgerufen wird, nach Elementen, die zum angegebenen CSS Selektor passen. In diesem Fall das ganze Dokument, und sie sucht<details>
Elemente, die ein Element mitclass="detailsGroup"
als Elternelement haben.
nein, nicht "Eltern" per se, sondern irgendwelche (gerne auch entfernte) Vorfahren. Das ist ein Unterschied, da im Selektor kein >
enthalten ist. Mit .detailsGroup > details
wäre das tatsächlich auf die Eltern beschränkt.
Liebe Grüße
Felix Riesterer
Vielen Dank für die ausführliche Erklärung jetzt habe ich aber ein Problem... Ich habe den neuen Code eingfügt und es funktioniert, aber jetzt kann ich die Datei nicht mehr speichern. Ich bekomme eine Meldung dass ein Fehler aufgetreten ist (Fehler Unknown).
<script type="text/javascript">
document.querySelectorAll(".menue details")
.forEach(d => d.addEventListener("toggle", detailsToggler));
function detailsToggler(ev) {
if (!ev.target.open) return;
let container = ev.target.closest(".menue");
for (let d of container.querySelectorAll("details")) {
if (d != ev.target)
d.open = false;
}
}
</script>
so habe ich den Code in meine Html datei eingefügt. Der div in dem alle Details drin sind hat bei mir die Klasse "menue" Ich hoffe ich habe jetzt nichts total offensichtliches übersehen und es gibt eine Lösung für das Problem. LG Arne
Hallo ArneS,
aber jetzt kann ich die Datei nicht mehr speichern
?!?!
Du kannst welche Datei wo nicht speichern? Und womit bearbeitest Du sie? Hast Du sie vielleicht in zwei Programmen gleichzeitig geöffnet und das eine blockiert das andere beim Speichern?
Wenn Du den Code in der von Dir gezeigten Form in ein HTML Dokument einbindest (am Ende des body bitte, sonst muss man noch einen ready-Handler bauen), sollte das aber funktionieren.
Rolf
hmm jetzt hat es funktioniert, da war ich wohl kurz etwas Panisch 😆. Trotzdem vielen dank für Antwort.
@@Rolf B
Welcher Vollpfosten hat eigentlich in der Spec vergessen hinzuschreiben, dass das toggle Event mit bubbles=true erzeugt ewrden sollte? Oder war das etwa sinistre Absicht?
Irgendwas werden sie sich vielleicht dabei gedacht haben, aber was? Ich hatte tatsächlich erst in MDN nachgesehn, ob’s blubbert, bevor ich an event delegation scheitere.
(Edit: Und bezüglich Code Quality muss ich noch eine Menge lernen)
Zum Beispiel sprechende Variablennamen:
.forEach(d => d.addEventListener("toggle", detailsToggler));
Wofür zum Deibel steht d
?
function detailsToggler(ev) {
Aus einem Event ein Evangelium zu machen, ist eine verbreitete Unsitte.
if (!ev.target.open) return;
Ach, so einfach ist das‽ 🤷♂️
In der Version kann man dann auch auf summary clicken, um das Ding wieder zu schließen.
😷 LLAP
Hallo Gunnar,
ich finde es in Lambdas unsinnig, die Kürze der Form durch aufgeblasene Variablennamen zu torpedieren. Was d ist, wird aus dem Kontext sofort klar.
Bei Block-Lambdas sieht es wieder anders aus.
Das Wort event
als Variablenname ist für mich von C# her verbrannt. Dort ist es ein reserviertes Wort, und bevor ich anfange, mir für jede Sprache separat zu merken, welche Worte reserviert sind und welche nicht, setze ich das Wort für mich lieber auf die Liste zu meidender Variablennamen.
Und ja, ich verwende im Büro C# und JS parallel, weil ich dort die Serverkomponenten mit C# erstelle.
Rolf
@@Rolf B
ich finde es in Lambdas unsinnig, die Kürze der Form durch aufgeblasene Variablennamen zu torpedieren. Was d ist, wird aus dem Kontext sofort klar. […]
Das Wort
event
als Variablenname ist für mich von C# her verbrannt.
Da irrt der Elevant. Du schreibst lesbaren Code nicht für dich, sondern für andere. Insbesondere Beispielcode hier im Forum.
😷 LLAP
@@Gunnar Bittersmann
PS: TIL, dass Firefox
:focus-visible
nicht aufdetails
-Elemente anwendet. 😞
Was für’n Unsinn! Der aktuelle Firefox kennt :focus-visible
generell noch nicht, sondern :-moz-focusring
. Und jenes wendet er auch auf details
-Elemente an.
Wenn man im Codepen
:focus:not(:-moz-focusring) {
outline: none;
}
:-moz-focusring {
outline: thin solid blue;
}
ergänzt, ist der Rahmen durchgängig blau, nicht schwarz gepunktet.
Allerdings erscheint der Rahmen auch bei Mausbedienung, was er nicht soll. Die Implementierung von :-moz-focusring
ist noch nicht so, wie sie für :focus-visible
sein soll.
Der 85er Firefox (gegenwärtig Developer Edition) macht’s richtig; er unterstützt :focus-visible
.
😷 LLAP