Infobox/Akkordeon mit details
Text-Info
- 30min
- einfach
- ● HTML
● JavaScript
(für das Akkordeon)
Ein disclosure widget ist ein UI-Element, das es ermöglicht, Seiteninhalte zu verstecken und mit einem Klick auf eine Zusammenfassung oder eine Überschrift zusammen mit einem Indikator (manchmal ein Dreieck oder ein Pluszeichen) zusätzliche Inhalte anzeigt.
Dieses Verhalten wird oft als „Akkordeon“ bezeichnet, vor allem wenn mehrere solcher aufklappbaren Elemente vorhanden sind. Einige Akkordeons sind exklusive Akkordeons, was bedeutet, dass höchstens eine der Angaben in diesem Akkordeon gleichzeitig geöffnet sein kann.
Früher konnte ein solches Akkordeon nur mit vielen Zeilen JavaScript verwirklicht werden. Dabei wurde jedoch oft auf eine Bedienbarkeit mit der Tastatur keine Rücksicht genommen. Das details-Element bietet nun eine zugängliche und einfache Alternative.
Inhaltsverzeichnis
Offenlegungswidget mit details
Das details-Element bezeichnet einen semantischen Abschnitt, der mit Text, Bildern (oder einem figure-Element, einem Formular oder auch anderen details) gefüllt werden kann. Mit ihm kann man Seiteninhalte verstecken und mit einem Klick auf summary aufklappen.
Überschrift mit summary
Mit summary können Sie dem Akkordeon eine Überschrift geben. Links daneben wird ein details-marker
-Pseudoelement in Form eines schwarzen Dreiecks angezeigt. Es verändert bei einer Zustandsänderung seine Richtung.
Ein Klick mit der Maus öffnet den versteckten Abschnitt. Alternativ bringt die Tab-Taste die Überschrift summary in den Fokus. Ein Klick auf Leertaste oder Enter ⏎ öffnet dann den Text.
open
Mit dem Klick auf die summary
wird details
das Attribut open angehängt. Um die Details direkt anzuzeigen, können Sie es auch direkt im HTML-Code notieren. Es eignet sich auch als Angriffspunkt, um das betreffende Element mit CSS zu gestalten:
<details open>
<summary>
Browser-News:
</summary>
<p>
Während Chrome, Opera und Safari das neue Element schon sehr lange unterstützen,
ist es in Firefox seit Version 49 verfügbar.
</p>
</details>
details[open] {
background: coral;
margin-bottom: 1em;
}
Gestaltung mit CSS
Wie das details-Element auf Ihrer Webseite dann aussieht, bleibt Ihnen und Ihrer Fantasie überlassen.
Formatierung des details-markers
Das Summary Element enthält ein kleines schwarzes Dreieck.
Wenn Sie ein summary-Element im Seiteninspektor überprüfen, entdecken Sie weitere, „versteckte“ Elemente im Shadow DOM:
In CSS3 kann der details-marker mit dem ::marker-Selektor ausgewählt und bedingt formatiert werden.[1]
Die Spezifikation nennt für die Marker-Box die Eigenschaften content
sowie sämtliche animation
- und transition
-Eigenschaften. Hinzu kommen text-combine-upright
, unicode-bidi
und direction
. Der Marker-Inhalt kann durch alle font-Eigenschaften sowie white-space
, text-transform
, letter-spacing
und color
beeinflusst werden.
Das Beispiel verwendet Pfeilsymbole aus dem Unicode-Block „Supplemental Arrows-C“ (U+1F871 und U+1F873). Wenn Ihr Computer diese Zeichen nicht darstellen kann, können Sie auch andere Pfeilzeichen wie ⮯ und ⮭ verwenden.
summary::-webkit-details-marker,
summary::marker {
content: " 🡳 "; /* Verwendung des "Pfeil abwärts"-Symbols anstelle des Dreiecks */
color: green;
font-size: 2em;
font-weight: bold;
transition: all 0.5s;
}
details[open] summary::-webkit-details-marker,
details[open] summary::marker {
content: " 🡱 "; /* Pfeil aufwärts anstelle des Dreiecks */
color: red;
}
Ersatz durch Pseudoelement
Wenn man zum Stylen des Markers Eigenschaften benutzen will, die von den Browsern noch nicht dafür vorgesehen sind, kann man ihn stattdessen auch ausblenden und dafür ein eigenes Pseudoelement erzeugen und formatieren:
summary {
position: relative;
}
summary::marker {
color: transparent;
}
summary::after {
content: "+";
position: absolute;
color: green;
font-size: 2em;
font-weight: bold;
right: 1em;
top: .2em;
transition: all 0.5s;
}
details[open] summary::after {
color: red;
transform: translate(5px,0) rotate(45deg);
}
Die display:
Eigenschaft gehört zu denen, die vom Marker nicht beachtet werden, deshalb wird einfach die Farbe auf transparent gesetzt.
Das ::after-Pseudoelement erhält eine absolute Positionierung am rechten Rand. Über die content-Eigenschaft erhält es ein Plus-Zeichen, das auf zusätzlichen Inhalt verweist.
Bei einer Änderung des open-Attributs wird es mit einem weichen Übergang um 45° gedreht und so zu einem X, das das Fenster wieder schließt.
Tooltip mit details
Ein Tooltip ist ein kleines Pop-up-Fenster in Anwendungsprogrammen oder Webseiten. Oft wird es mit einem abbr-Element realisiert, dessen title-Attribut dann ausgelesen wird. Mit details
geht es einfacher:
[role=button] {
background: var(--accent);
color: var(--background);
border-radius: 0 0.5em 0.5em;
border: thin solid var(--accent);
width: min-content;
padding: 0 1.5em 0.5em;
font-size: 1.5em;
line-height: 100%;
font-weight: bold;
}
details[open] [role=button] {
background: var(--background);
color: var(--accent);
}
details p {
position: relative;
padding: 1em;
border: thin solid var(--accent);
border-radius: 0 0.5em 0.5em;
}
details p::before {
content: ' ';
position: absolute;
width: 0;
height: 0;
top: -1em;
left: 20%;
margin-left: -1em;
border-style: solid;
border-width: 0 1em 1em 1em;
border-color: transparent transparent var(--accent) transparent;
}
Das summary-Element erhält jetzt das Aussehen eines Buttons. Damit sich dieser nicht über die gesamte Breite des verfügbaren Platzes erstreckt erhält er mit width: min-content
eine an den vorhandenen Inhalt angepasste Breite.
Bei einem Klick auf den (vermeintlichen) Button öffnet sich details p
als Sprechblase.
Akkordeon
Ein Akkordeon ist ein sehr nützliches Entwurfsmuster für progressive disclosure (englisch für schrittweise Offenlegung).[2] – wichtige Abschnitte werden hervorgehoben und mit einem Tap oder Klick können, wenn nötig, weitere Details geöffnet werden.
Information: details und Zugänglichkeit
Es gibt immer wieder Stimmen, die behaupten, dass das details-Element kein Akkordeon wäre. So würden eventuell darin vorhandene Überschriften (h1-h6) vom summary-„button“ geschluckt und wären so nicht mehr zugänglich.[3]
role="group"
[4]. Diese Rolle wird als "Name from author" definiert und benötigt entweder eine summary oder ein aria-label-Attribut oder ein aria-labelledby-Attribut.[5][6]HTML5 bietet mit dem details-Element eine bequeme, in allen modernen Browsern unterstützte Lösung. Allerdings gibt es derzeit keine Möglichkeit, den Übergang zwischen open und closed zu animieren, bzw. mehrere details-Elemente zu verknüpfen. In diesem Tutorial lernen Sie, wie Sie details-Akkordeons mit JavaScript so anreichern, dass sie als Fallback für alte Browser dienen können und mehr Komfort als eine reine HTML-Lösung bieten.
So bleibt das Design übersichtlich und zeigt wesentliche Informationen zuerst, während weiterführende Details leicht erreichbar sind. Oft können so unübersichtliche und gedrängt aussehende Seiten ansprechender präsentiert werden.
Wie so etwas früher aussah, kann man hier sehen:
<div id="accordion">
<button aria-expanded="false" aria-controls="collapsible-0">Section 1</button>
<div id="collapsible-0" aria-hidden="true">
<p>Inhalt 1</p>
</div>
<button aria-expanded="false" aria-controls="collapsible-1">Section 2</button>
<div id="collapsible-1" aria-hidden="true">
<p>Inhalt 2</p>
</div>
</div>
Das Akkordeon besteht aus Buttons und einem dazugehörenden div. Um diesen Zusammenhang auch für Screenreader klarzustellen, erhalten die Buttons ein aria-controls-Attribut, dass auf die id
des dazugehörenden divs verweist. Jeder Button erhält ein aria-expanded-Attribut, dass den jeweils geschalteten Zustand anzeigt, was auch mit CSS sichtbar gemacht wird.
Fazit: Die aria-labels gaben den bedeutungslosen buttons und divs einen Sinn, durch das Vorlesen aller aria-Attribute wurde dieser Segen aber oft zum Fluch, da die vielen Attribute doch vom eigentlichen Inhalt ablenkten!
HTML
Es wäre schön, wenn das Akkordeon nicht abrupt, sondern sich mit einem weichen Übergang aufschieben würde. Leider ist dies mit CSS alleine nur eingeschränkt möglich:
<details>
<summary>
immer sichtbare Überschrift
</summary>
<div>
aufzuklappender Inhalt
</div>
</details>
details > div {
padding: .5em;
overflow: hidden;}
details[open] > div {
animation: sliding 1s forwards;
}
@keyframes sliding {
0% {
height: 0;
}
100% {
height: 15em;
}
}
Im Beispiel wird die Höhe des div-Containers aminiert. Beim Setzen des open-Attribut wird die animation sliding
gestartet. Hierbei benötigt man aber einen festen Wert (hier: 15em), der bei einer Veränderung des Inhalts angepasst werden muss.
Um die Interaktion (weiches Öffnen des details-Elements) zu verbessern, kann man JavaScript einsetzen:
JavaScript
Die Funktionalität des Beispiels ist bereits vorhanden; mit einem Klick springt das details-Element abrupt von "zu" auf "auf" und umgekehrt. Mit JavaScript können Sie nun zusätzlichen Komfort einbauen:
weicher Übergang
Mit CSS ist eine transition der Höhe nur möglich, wenn beide Zustände feste Werte erhalten, der Wert auto
für die „normale“, durch den Inhalt bestimmte Höhe bewirkt wieder ein Ausklappen.
JavaScript soll nun nur den Aufklapp-Mechanismus mit einem weichen Übergang versehen. Dabei soll die Höhe des im details umschlossenen Containers automatisch ermittelt werden.
const detailElements = document.querySelectorAll("details"),
style = document.createElement("style");
let stylecontent = "";
detailElements.forEach(function(detailElement,index){
stylecontent +=
`details[open]:nth-of-type(${index+1})height:${detailElement.getBoundingClientRect().height}px;}`;
detailElement.removeAttribute("open");
stylecontent +=
`details:nth-of-type(${index+1}){height:${detailElement.getBoundingClientRect().height}px;}`;
})
style.innerText = stylecontent;
document.head.appendChild(style);
Über querySelectorAll werden alle details-Elemente selektiert und einer node list mit Namen detailElements
geschrieben.
Zusätzlich wird ein style-Element erzeugt. Mit forEach wird für jedes details-Element der Liste mit getBoundingClientRect() die Höhe der Box einmal im geöffneten und einmal im geschlossenen Zustand ermittelt und jeweils in einem template-literal als CSS-Regelsatz der Variable stylecontent
zugewiesen:
`details[open]:nth-of-type(${index+1}){height:${detailElement.getBoundingClientRect().height}px;}`;
CSS-Selektor ist der Elementselektor details
mit dem Attribut-Selektor [open] und dann dem nth-of-type-Selektor, der mit index+1
die entsprechende Stelle im DOM erhält.
Diese Anweisungen werden mit innerText in das style-Element geschrieben und dies mit appendChild in den Elementbaum eingehängt.
Beim Öffnen und Schließen können nun die festen Pixel-Werte für die Animation verwendet werden.
Exklusives Akkordeon
Ein exklusives Akkordeon ist ein UI-Element, in dem mehrere Aufklappelemente so verbunden sind, dass höchstens eine der Angaben in diesem Akkordeon gleichzeitig geöffnet sein kann.
In diesem Beispiel werden drei details-Elemente in einem div gruppiert. Bei einem Klick auf ein summary-Element wird das betreffende details-Element geöffnet, alle anderen details-Elemente geschlossen:
document.querySelectorAll('.detailsGroup details')
.forEach(details => details.addEventListener('toggle', detailsToggler));
function detailsToggler(event) {
if (!event.target.open) return;
let container = event.target.closest('.detailsGroup');
for (let details of container.querySelectorAll('details')) {
if (details != event.target)
details.open = false;
}
}
Mit document.querySelectorAll('…') werden alle Elemente, die zum angegebenen CSS Selektor passen, ausgewählt. In diesem Fall details-Elemente, die ein Element mit class="detailsGroup"
als Elternelement haben.
Das Ergebnis von querySelectorAll ist eine NodeList. 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.
details => …
ist eine Pfeilfunktion und eine Kurzschreibweise für function(details) { return … }
. Für jedes details-Element wird addEventListener aufgerufen, um für das toggle-Event die Funktion detailsToggler
als Eventhandler zu registrieren.
Die Funktion detailsToggler
sucht mittels der closest-Methode das nächstliegende Elternelement, 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. Nun wird geprüft, ob das gefundene details-Element mit dem Event-Target übereinstimmt. Nur, wenn das nicht der Fall ist, wird es geschlossen. Andernfalls würde das frisch geöffnete details ebenfalls gleich wieder zugemacht.
Ausblick
Optimal wäre es wenn ein solches Exklusives Akkordeon nicht mit JavaScript programmiert, sondern bereits in nativem HTML vorhanden wäre. Die open-ui.org schlägt vor, mehrere details-Elemente über ein gemeinsames name-Attribut (wie bei Radio-Buttons) zu verbinden und dann bei einem Öffnen alle anderen zu schließen. Ein entsprechender Vorschlag liegt bereits bei der WHATWG.[7]
Siehe auch
- JavaScript/Tutorials/Zusammenfassung für längere Artikel
Gerade bei längeren Artikeln ist es angebracht, vorab einige Informationen zum Artikel zu liefern, damit der Besucher der Seite entscheiden kann, ob dieser Artikel für ihn der richtige ist.
Quellen
- ↑ MDN: ::marker
- ↑ smashing magazine: Designing The Perfect Accordion
The Barebones Of An Accordion
sehr ausführlicher Grundlagenartikel, der Anwendungsfälle und besonders die Gestaltung des markers mit vielen Beispielen zeigt. - ↑ Dave Rupert: Why <details> is Not an Accordion
tl;dr - <summary> is a button and buttons eat semantics - ↑ W3C: details
- ↑ W3C: ARIA specs
- ↑ hasellinclusion: Accessible accordions part 2 – using <details> and <summary>
Sehr ausführlicher Artikel, der die Zugänglichkeit in allen Browsern und Readern testet.
tl;dr - In NVDA werden state changes nicht vorgelesen. (https://github.com/nvaccess/nvda/issues/8631) - ↑ Add name attribute for grouping details elements into an exclusive accordion (github.com/whatwg)
Es erfüllt genau die Anforderungen an ein Akkordeon und ist im Gegenteil zu vielen mit jQuery vorgefertigten, aber auch rein CSS-basierten Beispielen in allen unterstützten Browsern mit seinem Standardverhalten zugänglich, d. h. auch mit der Tastatur zu öffnen und zu schließen.