Accordion – Effekt nur CSS

Accordion oder Akkordeon - Effekt nur CSS, kein Javascript

Als einfachste Lösung für ein platzsparendes Akkordeon galt früher jQuery, aber wer will eine Javascript-Library mit zig-Kilobyte laden, nur um einen einfachen Effekt in Szene zu setzen? Für die Anhänger der reinen CSS-Lösungen: So funktioniert der Checkbox-Hack.

23-02-02 SITEMAP CSS HTML JS Basis JS Web Tutorial SVG

Kleiner Ausflug in HTML-Formulare

Der Akkordeon-Effekt hier basiert auf einem input type="radio" -Feld. Ist der Zustand des input-Felds checked, öffnet sich das jeweilige Panel des Akkordeons und schließt sich mit dem nächsten Klick.

input type="radio" kennen wir als Optionen in einem Formular.

Rot Grün Blau Gelb

Es ist das gemeinsame name-Attribut, das die Radio-Buttons synchronisiert, so dass immer nur ein Feld den Wert checked aufweist.

<input type="radio" name="myradio" value="rot"> Rot
<input type="radio" name="myradio" value="grün"> Grün
<input type="radio" name="myradio" value="blau"> Blau
<input type="radio" name="myradio" value="gelb"> Gelb

Ein label-Tag ist über das id bzw. for-Attribut mit seinem Eingabefeld verbunden – gleich, ob das label-Markup vor oder irgendwo nach dem Eingabefeld notiert ist.

Ein Klick auf das label-Element löst den Radio-Button genauso aus wie der Klick auf das input-Element. Das input-Element selber kann mit display:none verborgen bleiben. Dieses Verhalten macht eigene Stile für Checkboxen und Radiobutton einfacher als appearance und stelle auch für alte IEs keine Herausforderung dar.

<span>
    <input type="radio" name="myradio2" value="Rotes T-Shirt" id="rot"> 
    <label for="rot" class="bigbutton">checked</label>
</span>

<span>
    <input type="radio" name="myradio2" value="Grünes T-Shirt" id="grün"> 
    <label for="grün" class="bigbutton">checked</label>
</span>

Das CSS für die Label-Buttons: input-Tag verbergen, anstelle dessen die label-Elemente kräftig aufgeblasen. input:checked~.bigbutton ist einerseits ein Attribut-Selektor, andererseits ein indirekter Nachbar-Selektor (~).

Damit das Label-Element auf einen Klick / Touch reagiert, müssen input und label nur unter einem gemeinsamen Elternelement sitzen.

input[name="myradio2"] { display: none }

.bigbutton {
   background: #fff;
   color: white;
   border: 16px solid #28A3D7;
   transition: 0.5s;
}

input:checked~.bigbutton { 
   background: #0E6F98; 
   transition: 0.5s;
}  

Accordion mit CSS :checked

Das war ein langer Vorspann, dafür ist der Trick hinter dem Akkordeon ohne Javascript hoffentlich besser verständlich.

  • Liquorice wafer lollipop sesame
  • snaps gummi bears. Wafer jelly beans chupa chups cotton candy
  • caramels carrot cake topping oat cake.
  • Cake carrot cake marshmallow cheesecake cake lemon drops pudding apple pie.
  • Chocolate gingerbread marshmallow croissant.
  • Liquorice jujubes cake ice cream cake liquorice croissant ice cream.
  • Lollipop jelly-o fruitcake chocolate cake tootsie roll marzipan dragée halvah.
  • Chocolate gingerbread marshmallow croissant.
  • Liquorice jujubes cake ice cream cake liquorice croissant ice cream.

Fruitcake marshmallow sugar plum soufflé biscuit.

Sesame snaps pie lemon drops.

In einem Element mit der CSS-Klasse panel kann alles stecken: Ungeordnete Listen wie in diesem Beispiel, Texte oder Bilder.

<div class="accordion">          
   <div>
      <input type="radio" name="acc" id="Liquorice" checked>
      <label for="Liquorice"><b>❦</b> Liquorice</label>
      <ul class="panel">
         <li>Liquorice wafer lollipop sesame</li>
         <li>snaps gummi bears. Wafer jelly beans chupa chups cotton candy</li>
         <li>caramels carrot cake topping oat cake.</li>
      </ul>
   </div>
   <div>…</div>
   <div>…</div>
</div> <!-- Ende accordion -->

Jede der drei Ebenen besteht aus einem input-Element vom Typ radio, die alle durch dasselbe name-Attribut miteinander verbunden sind. So kann immer nur ein Radio-Button aktiv sein (checked).

Jedes Input-Element hat eine eindeutige ID, die mit dem for-Attribut des label-Tags übereinstimmt.

Etwas Formular-Magie: Das Input-Feld ist nicht sichtbar (display:none), aber das label-Tag mit dem passenden for-Attribut bekommt den Mausklick genauso mit.

Panel animieren

.accordion input{
  display: none;
}

.accordion .panel {
  margin: 0 auto;
  height: 0;
  overflow:hidden;
  background-color: white;
  line-height: 1.4;
  padding: 0 20px;
  box-sizing: border-box;
  transition: all 0.5s;
}

.accordion input:checked~.panel {
  height: auto;
  color: #333;
  padding: 20px;
  transition: all 0.5s;
}

CSS für label

Beim Öffnen eines Akkordeon-Fachs ändert das erste Beispiel oben nur die Hintergrundfarbe von Hellblau hsl(200,80%,80%) zu Dunkelblau hsl(200,80%,50%). Dabei ist immer ein Fach geöffnet.

.accordion label {
  cursor: pointer;
  background-color: hsl(200,80%,80%);          /* Hellblau */
  border-bottom: 2px solid hsl(200,80%,80%);
  display: block;
  padding: 15px;
  width: 100%;
  color: #fff;
  font-weight: 400;
  box-sizing: border-box;
  z-index: 100;
}

.accordion input:checked+label {
  background-color: hsl(200,80%,50%);            /* Dunkelblau */
}

An einem Stück, ohne Anspruch auf Vollständigkeit: Akkordeon mit CSS – (fast) ohne Javascript

Plus / Minus im label

Ein Plus / Minus wird den Benutzer besser informieren, dass die Akkordeon-Fächer geöffnet und geschlossen werden können, aber es gibt kein uncheck-Event in CSS 3 und es scheint, dass es auch in CSS 4 dabei bleibt.

Für das Schließen eines Panels springt ein zusätzliches input-type-radio Element mit demselben name-Attribut ein.

  • Liquorice wafer lollipop sesame
  • snaps gummi bears. Wafer jelly beans chupa chups cotton candy
  • caramels carrot cake topping oat cake.
  • Cake carrot cake marshmallow cheesecake cake lemon drops pudding apple pie.
  • Chocolate gingerbread marshmallow croissant.

Fruitcake marshmallow sugar plum soufflé biscuit.

Sesame snaps pie lemon drops.

Für das Schließen der Panels kommt bei jedem Fach des Akkordeons ein weiteres input type="radio" mit demselben name-Attribut (ac) hinzu.

<div class="acc">          
   <div class="choice">
      <input type="radio" class="open" name="ac" id="Liq" >
      <input type="radio" class="close" name="ac" id="Liq-close" >
      <label for="Liq">Liquorice</label><label class="close" for="Liq-close"></label>
      <ul class="panel">
         <li>Liquorice wafer lollipop sesame</li>
         <li>snaps gummi bears. Wafer jelly beans chupa chups cotton candy </li>
         <li>caramels carrot cake topping oat cake.</li>
      </ul>
   </div>
   …
   …
</div>

Die input-Tags sind natürlich wieder nicht sichtbar.

.acc input[name="ac"] { display:none }

Das Panel öffnet sich wie zuvor bei einem Klick auf das Label des Akkordeon-Fachs.

.acc .panel {
  margin: 0;
  height: 0;
  overflow:hidden;
  background-color: hsla(12, 50%, 95%);
  line-height: 1.5;
  padding: 0 2rem;
  box-sizing: border-box;
  transition: 0.5s;
}

.acc input.open:checked~.panel {
  height: auto;
  padding: 2rem;
  transition: 0.5s;
}

Plus- und Minus-Zeichen entstehen als Pseudo-Klassen. label:nth-child(odd) ist das erste Label, label:nth-child(even) das zweite.

.acc label:nth-child(odd)::after  { 
  content: "+"; 
  float:right; 
}

/* Fach geöffnet, dann verschwindet das Plus-Zeichen */
.acc input.open:checked ~ label:nth-child(odd)::after { content: ""; }

/* und statt dessen erscheint das Minus-Zeichen */
.acc input.open:checked ~ label.close::after {
  content: "– ";
}

Ein Klick auf das Minus-Zeichen aktiviert den Radio-Button mit demselben name="ac", so dass die Radio-Buttons, die für das Öffnen zuständig sind, jetzt unchecked sind.

Das CSS für das Akkordeon ist ein CSS-Grid mit template-areas, also nichts für den barocken IE11. Wer sich allerdings die Mühe macht und IE11-kompatibles CSS für das Design des Akkordeons aufsetzt: Das Auf- und Zuklappen des Accordion-Effekts mit purem CSS funktioniert auch in IE11.

Plus- und Minus-Symbol sitzen nicht an derselben Stelle – vielleicht erbarmt sich ein Leser und grübelt über eine bessere Lösung.

An einem Stück:

Das Auf und Ab

Das Auf- und Abschwingen des Akkordeon-Effekts lässt sich nur durch eine feste Höhe für die Ebenen des Akkordeons lösen oder letztendlich doch wieder per Javascript.

Ein paar Zeilen Javascript müssten die maximale Höhe des Akkordeons bestimmen und das CSS in ein Stylesheet schreiben. Das Script kommt ans Ende der Seite vor das schließende body-Tag.

<script>
{
	const acco = document.querySelectorAll (".accordion>div");
	let maxHeight = 0;
	let labelTotal = 0;
	for (let i=0; i<acco.length; i++) {
		acco[i].querySelector("input").checked = true;
		if (acco[i].clientHeight > maxHeight) {
			maxHeight = acco[i].clientHeight;
		}
		labelTotal = labelTotal + acco[i].querySelector("label").clientHeight;
	
	}
	acco[0].querySelector("input").checked = true;
	document.querySelector(".wrap").style.height = (maxHeight + labelTotal) + "px";
}
</script>

Accordion input type="checkbox"

Wenn mehrere Panels des Accordions geöffnet bleiben sollen, werden Checkboxen anstelle von Radio-Buttons eingesetzt.