Infobox/Akkordeon mit details
- 30min
- einfach
-
- HTML
- JavaScript
(für die Registerkarten)
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.
summary::-webkit-details-marker,
summary::marker {
content: " 🡳 "; /* Verwendung des "Pfeil"-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: " 🡱 ";
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, summary::-webkit-details-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. Safari unterstützt (Stand 12/2023) ::marker noch nicht und benötigt ::-webkit-details-marker.
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.
Hauptartikel: Infobox/Tooltips mit Popover
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 sich 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>
Das details-Element enthält eine summary und weitere, aufzuklappende Inhalte in einem div-Element.
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.
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. Optimal wäre es wenn ein solches Exklusives Akkordeon nicht mit JavaScript programmiert, sondern bereits in nativem HTML vorhanden wäre.
Die WHATWG übernahm den Vorschlag der open-ui.org, mehrere details-Elemente über ein gemeinsames name-Attribut (wie bei Radio-Buttons) in einer semantischen Gruppe zu verbinden.[7] Mehrere details-Elemente mit demselben name-Wert verhalten sich wie ein exklusives Akkordeon.
<details name="acc" >
<summary> aufklappbar - Wie funktioniert das? </summary>
<div class="content">
</div>
</details>
<details name="acc">
<summary> Sind eigene Titel-Texte möglich? </summary>
<div class="content">
</div>
</details>
<details name="acc" open>
<summary> Exklusives Akkordeon </summary>
<div class="content">
</div>
</details>
In diesem Beispiel werden drei details-Elemente mit einem gemeinsamen name-Attribut gruppiert. Bei einem Klick auf ein summary-Element wird das betreffende details-Element geöffnet, alle anderen details-Elemente geschlossen.
Dies funktioniert (Stand: September 2024) in allen modernen Browsern. In älteren Browsern bleiben die anderen details-Elemente aufgeklappt - graceful degradation, bzw.progressive enhancement für Browser, die dies bereits unterstützen.
Registerkarten
Unter dynamischen Tabs (engl. Tabbed interfaces oder Tab Panels) versteht man das Präsentieren von Inhalten in Registerkarten. Reiter wie in einer Hängeregistratur verweisen auf die vorhandenen Registerkarten. Da nur die ausgewählte Registerkarte angezeigt wird, ist dies eine platzsparende, übersichtliche und visuell intuitive Art Inhalte zu präsentieren.
Aufbauend auf dem exklusiven Akkordeon können wir nun Registerkarten bauen, die den Inhalt bei einem Klick auf den jeweiligen Reiter anzeigen:
HTML
<ul role="tablist" id="tablist">
<li id="link1" role="tab" aria-controls="panel-1" aria-selected="true">1 - Button</li>
<li id="link2" role="tab" aria-controls="panel-2" aria-selected="false">2 - Button</li>
<li id="link3" role="tab" aria-controls="panel-3" aria-selected="false">3 - Button</li>
</ul>
<div id="tabcontent">
<div id="panel-1" role="tabpanel" aria-labelledby="link1" aria-hidden="false">
<h3>Inhalt 1</h3>
<p> Hier kommt was hin!</p>
</div>
<div id="panel-2" role="tabpanel" aria-labelledby="link2" aria-hidden="true">
<h3>Inhalt 2</h3>
<p> Hier kommt was hin!</p>
</div>
<div id="panel-3" role="tabpanel" aria-labelledby="link3" aria-hidden="true">
<h3>Inhalt 3</h3>
<p> Hier kommt was hin!</p>
</div>
</div>
</div>
</section>
Früher bestand ein Tab Panel aus einer Navigation in Form einer Liste und einem div mit drei Kindelementen, die über aria-labelledby-Attribute mit der id
der Buttons verbunden waren. Deren aria-controls-Attribut zielte auf die id
der Listenelemente.
Elemente, die Aussehen und Darstellung ändern, haben im Allgemeinen Zustände, die durch Benutzeraktionen geändert werden. So ändern die einzelnen Tabs ihren Zustand von „nicht ausgewählt“ auf „ausgewählt“, wenn sie geklickt werden und werden plötzlich sichtbar. Dies kann mit den Aria-Attributen aria-selected und aria-hidden ausgezeichnet und durch CSS-Selektoren sichtbar gemacht werden.
Die Steuerungselemente waren funktionslose Listenelemente, denen erst mit JavaScript die Möglichkeit zur Benutzerinteraktion hinzugefügt wurde.
Heute verwenden wir nur unser exklusives Akkordeon, deren details-Elemente Semantik und Rollen bereits mitbringen:
<div class="tabs">
<details name="tab" >
<summary> Registerkarten</summary>
<div class="content">
</div>
</details>
<details name="tab">
<summary> Standardverhalten</summary>
<div class="content">
</div>
</details>
<details name="tab" open>
<summary> Barrierefreiheit </summary>
<div class="content">
</div>
</details>
</div>
Die drei details-Elemente sind in einem Container mit der Klasse tabs
umschlossen. Über den gemeinsamen Namen tab
wird in modernen Browsern die Funktionalität des gegenseitigen Zuklappens ermöglicht.
CSS
Nun wird es Zeit, das Tab Panel mit dem gewünschten CSS zu gestalten.
.tabs details {
display: inline-block;
}
.tabs summary {
background-color: lightgrey;
border: thin solid black;
border-bottom: none;
border-radius: 0.5em 0.5em 0 0;
font-weight: bold;
height: 1.5em;
width: 10em;
padding: 0.5em 0.5em 10px;
}
.tabs .content {
position: absolute;
left: 0;
right: 0;
background: white;
border: thin solid #ccc;
padding: .5em;
}
Dieses Akkordeon wird nun durch das Standardverhalten der details-Elemente gesteuert - Zugänglichkeit für Tastaturnutzer inklusive. Ein Einsatz von JavaScript ist nicht mehr nötig!
Siehe auch
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)