Ebene 11 Webentwicklung . AutoCAD . Schulung

Accordion, Slider, Tabs & Co. mit purem CSS Es muss nicht immer Javascript sein

In Zeiten von jQuery und unzähligen darauf basierenden Lösungen, die mit ein wenig Copy and Paste in die eigene Seite eingebaut sind, übersieht man mitunter die Möglichkeiten, die HTML und CSS von Hause aus mitbringen. In diesem Artikel wird exemplarisch eine Technik vorgestellt, die als Grundlage für die verschiedensten Arten von Slidern, Tabs, Accordions u.ä. dienen kann.

Die Idee

Egal ob Slider oder Tabs oder irgendwas anderes in die Richtung, letzten Endes geht es immer um die Steuerung der Sichtbarkeit/Position von Elementen über einen Mausklick (oder vergleichbare Aktionen). Ein klassischer Ansatz hierfür ist die Verwendung der Pseudoklasse :target. Dieser funktioniert im Grunde auch prima, allerdings kommt man doch relativ schnell an die Grenzen der Komfortabilität. Wesentlich mehr Flexibilität bietet da der Weg über den Einsatz von input-Elementen (Radiobuttons und/oder Checkboxes). Auf deren Status lässt sich mit der Pseudoklasse :checked zugreifen, womit wir unsere Steuerlemente haben. Mehr braucht es für die Funktionalität nicht!

Der Mechanismus

Ein simpler HTML-Code könnte demnach wie folgt aussehen:


Alles was innerhalb des div-Elements steht wird im nächsten Schritt per css angesprochen.

Das können beliebige Elemente sein - Überschriften, Absätze, Listen etc.

Um nun das dem input folgende div anzusprechen, können wir einen Nachbarselektor verwenden. Hier würde sowohl der direkte (F + E) als auch der indirekte (F ~ E) funktionieren, damit wir später etwas flexibler sind, nehme wir den indirekten und weisen einen Rahmen sowie ein wenig Innenabstand zu:

input ~ div {
	border: 1px solid #ddd;
	padding: .4em;
}

Okay, zugegebenermaßen soweit nicht besonders spektakulär. Spaßig wird es aber, wenn wir noch eine Kleinigkeit ergänzen. Mit der Pseudoklasse :checked für das Element input bekommen wir eine Möglichkeit auf den Status dieses Elements zu reagieren. Ändern wir z.B. die Opazität bei aktivierter Checkbox:

input:checked ~ div {
	opacity: 0;
}

Fallback

Die Pseudoklasse :checked wird von jedem modernem Browser und dem IE ab Version 9 verstanden. In diesem einfachen Beispiel kein wirkliches Problem - in älteren Browsern wird halt nichts ausgeblendet.

Denken wir aber einen Schritt weiter, so kommen wir relativ schnell zu einem Szenario, dass wir aus einer Menge von Elementen immer nur eines einblenden möchte (z.B. bei einem klassischen Accordion). Es liegt also nahe, erstmal alle Elemente auszublenden und erst im nächsten Schritt das gewünschte Element gezielt wieder einzublenden, z.B. so:

input ~ div {
	opacity: 0;
}

input:checked ~ div {
	opacity: 1;
}

Das Problem dabei ist, dass auch Browser, die Pseudoklasse :checked nicht verstehen, die Inhalte prima ausblenden, nur das Einblenden schlägt bei diesen natürlich fehl … wir sehen, dass wir nichts sehen. Dieser Problematik können wir jedoch relativ leicht begegnen, indem wir sowohl das Ein- als auch das Ausblenden per Pseudoklasse regeln. Alles was wir dazu noch brauchen ist die Negationspseudoklasse :not(s). Klingt schlimmer als es ist, der CSS-Teil verändert sich nur marginal:

/* allgemeine Styles für alle Browser */
input ~ div {
}

/* Ausblenden, wird nur von modernen Browsern interpretiert */
input:not(:checked) ~ div {
	opacity: 0;
}

/* Einblenden, wird nur von modernen Browsern interpretiert */
input:checked ~ div {
	opacity: 1;
}

Für den Fall, dass der Browser die Pseudoklassen nicht versteht, werden so auf jeden Fall alle Inhalte angezeigt. Sieht vielleicht nicht so hübsch aus wie geplant, aber es geht immerhin kein Inhalt verloren.

Da in der Praxis im Regelfall nur der IE in seinen alten Versionen vorkommt, reicht es zumeist, diesem mit ein wenig Javascript auf die Sprünge helfen. Eine relativ einfach zu integrierende Lösung ist selectivizr (http://selectivizr.com/).

Ein kleines Beispiel

Der oben aufgezeigte Mechanismus lässt sich natürlich in eine hübsche Verpackung hüllen. Zum einen durch Einführung von Elementen, mit denen wir den Status der Checkboxes steuern können - genau: das gute, alte label. Zum anderen durch ein paar Zeilen CSS, mit denen die einzelnen Elemente aufgehübscht werden. Bauen wir als Beispiel eine simple Box, die wir bei Bedarf ein- und ausblenden können.

Im ersten Schritt ergänzen wir den HTML-Code um zwei label-Elemente. Für die Steuerung würde natürlich auch eines ausreichen, aber um passend zum Status der Checkbox eine sinnvolle Beschriftung anzuzeigen, werden wir uns mit zweien leichter tun. Die ganze Box verpacken wir noch in ein div-Element. Je nach Szenario kann hier natürlich auch jedes andere Element verwendet werden - wenn es also etwas semantisch passenderes gibt, nur zu.

Hier steht ein toller Inhalt, der beliebige Elemente enthalten kann:

  • Listen
  • Bilder

Der Mechanismus ist identisch zum oben skizzierten, wird hier aber noch auf die Sichtbarkeit des passenden label-Elements erweitert. Der Rest des Codes dient nur der Optik und kann natürlich komplett nach eigenen Bedürfnissen angepasst werden. Auch für die Funktionalität gibt es selbstverständlich einige Alternativen zur Opazität - einfach mal probieren.

.toggleBox {
	position: relative;
	border: 1px solid #ddd;
}

/* Ausblenden des input-Feldes */
.toggleBox input {
	position: absolute;
	left: -99999px;
}

/* Gestaltung der labels */
.toggleBox label {
	display: block;
	background: #68B022;
	color: #fff;
	padding: .4em;
	text-align: center;
	cursor: pointer;
}

.toggleBox label:hover {
	background: #ddd;
}

/* Der Aufklappmechanismus */
.toggleBox input:not(:checked) ~ div {
	opacity: 0;
	height: 0;
}

.toggleBox input:checked ~ div {
	opacity: 1;
	padding: .8em;
	-webkit-transition: opacity 1s ease-in-out;
	-moz-transition: opacity 1s ease-in-out;
	-ms-transition: opacity 1s ease-in-out;
	-o-transition: opacity 1s ease-in-out;
	transition: opacity 1s ease-in-out;
}

/* Steuerung der Sichtbarkeit der labels */
.toggleBox input:not(:checked) ~ .close,
.toggleBox input:checked ~ .open {
	display: none;
}

Fazit

Die Pseudoklasse :checked ermöglicht es, an vielen Stellen auf den Einsatz von Javascript zu verzichten. An die Grenzen stößt man immer dann, wenn es an „richtige” Programmierung geht. Berechnungen, zeitgesteuertes ändern von Objekten und ähnliche Dinge sind nachwievor mit CSS nicht oder nur vergleichsweise umständlich lösbar (z.B. Keyframes Animation mit CSS3). Die Browserunterstützung ist relativ gut, was einen trotzdem nicht davon abhalten sollte einen sinnvollen Fallback einzubauen.

So sieht es aus

Hier steht ein toller Inhalt, der beliebige Elemente enthalten kann:

  • Listen
  • Bilder
.toggleBox {
	position: relative;
	border: 1px solid #ddd;
}

/* Ausblenden des input-Feldes */
.toggleBox input {
	position: absolute;
	left: -99999px;
}

/* Gestaltung der labels */
.toggleBox label {
	display: block;
	background: #68B022;
	color: #fff;
	padding: .4em;
	text-align: center;
	cursor: pointer;
}

.toggleBox label:hover {
	background: #ddd;
}

/* Der Aufklappmechanismus */
.toggleBox input:not(:checked) ~ div {
	opacity: 0;
	height: 0;
}

.toggleBox input:checked ~ div {
	opacity: 1;
	padding: .8em;
	-webkit-transition: opacity 1s ease-in-out;
	-moz-transition: opacity 1s ease-in-out;
	-ms-transition: opacity 1s ease-in-out;
	-o-transition: opacity 1s ease-in-out;
	transition: opacity 1s ease-in-out;
}

/* Steuerung der Sichtbarkeit der labels */
.toggleBox input:not(:checked) ~ .close,
.toggleBox input:checked ~ .open {
	display: none;
}

Hier steht ein toller Inhalt, der beliebige Elemente enthalten kann:

  • Listen
  • Bilder

Kommentare (27)

    • Geschrieben von: Hermann
    • am: 19.02.2015 um 18:33 Uhr

    Hey, ich kenne mich mit CSS so gut wie gar nicht aus. Zum Thema ein- und ausblenden, denke ich, wäre es naheliegender, wenn man beim Aufruf der Seite „aufklappen“ angezeigt bekäme, also der Inhalt nicht angezeigt werden würde und nur nach Bedarf aufgeklappt würde. Wie sähe das Beispiel dann aus?

    • Geschrieben von: Jan
    • am: 20.02.2015 um 10:06 Uhr

    Einfach das input-Element vorgabemäßig nicht checken, also checked="checked" rauslöschen.

    • Geschrieben von: Daniel
    • am: 04.02.2016 um 19:53 Uhr

    Eine interessante Variante eines Sliders. Ich versuche so eine "css-only-Variante" gerade in eine Joomla-Seite einzubauen (in ein Custom-Html Modul). Ich habe nur gerade keine Idee, wie/wo ich die CSS Datei hinterlegen kann.
    Haben Sie einen Tipp, wie ich das umsetzen kann?

    Vielen Dank im Voraus!
    Daniel H.

    • Geschrieben von: Daniel H.
    • am: 05.02.2016 um 07:54 Uhr

    Hallo nochmal, meine Frage hat sich geklärt. Es war einfach die Template CSS Datei, in die ich die CSS Anweisungen hineinkopieren musste.

    Vielen Dank trotzdem für den tollen Slider!

    • Geschrieben von: Mike
    • am: 13.02.2016 um 02:19 Uhr

    Hi!
    Wunderbare schlanke Umsetzung! Danke! Daumen hoch!
    Gesucht, gefunden, umgebaut & eingebaut.

    Jetzt hab ich nur ein Problem:
    Habe nach dem Inhalt ein Formular eingebaut. Dieses lässt sich jetzt nur ausfüllen/abschicken wenn die toggleBox aufgeklappt ist. Das Formular ist also irgendwie mit dem input-Elemt das zur Steuerung zum Aufklappen genutzt wird, verbunden. :-(

    Hast du nen Tipp?

    PS: Eigentlich ist das Formular in dem ich hier poste der Beweis dass es ne Lösung gibt. Aber ich komm nicht dahinter was du hier anders machst :-)

    • Geschrieben von: rifki
    • am: 21.02.2016 um 16:03 Uhr

    Hallo, ein sehr eleganter script! Google kann es ohne probleme Crawlen. Habe aber folgendes Problem damit:
    Wenn der Text aufgeklappt ist, ist der Footer Abstand mit dem Ende der Seite ok, also normal (vgl. http://heels-high.net/mail1.jpg
    Wenn ich zuklappe gibt es einen Abstand zum Ende der Seite. So hoch wie eben der Text hoch ist (vgl. http://heels-high.net/mail2.jpg).

    Ich habe wie beschrieben checked="checked" rausgelöscht…
    Wie kann ich das ändern? Kann mir bitte jemand helfen, vielen Dank.

    • Geschrieben von: Jan
    • am: 23.02.2016 um 08:40 Uhr

    @Mike: Ohne den Code zu sehen schwierig. Hast Du ein Beispiel dazu?

    @rifki: Meine Vermutung wäre, dass Du die Höhe im ausgeblendeten Zustand nicht auf Null gesetzt hast (vgl. Zeile 29 im CSS-Teil des Beispiels).

    • Geschrieben von: Marcel
    • am: 21.03.2016 um 13:19 Uhr

    Hi,
    erstmal vielen Dank für diese tolle Lösung :).
    Darf ich den Code auf meiner eigenen Website verwenden oder gibt es dafür Bedingungen die ich beachten muss?
    Mit freundlichem Gruß
    Marcel

    • Geschrieben von: Jan
    • am: 21.03.2016 um 19:17 Uhr

    Alle Codeschnipsel, die ich hier auf der Seite veröffentliche, können gerne in eigenen Projekten verwendet werden - egal ob als Anregung für eigene Basteleien oder Eins-zu-Eins-Kopie. Bei der Weitergabe an Dritte gilt: bitte Quelle angeben und kein Geld damit verdienen.
    Texte und Bilder bitte nur mit ausdrücklicher Genehmigung verwenden.

    • Geschrieben von: Sebastian
    • am: 11.10.2016 um 17:21 Uhr

    Hallo, wie kann ich es anstellen, dass ich mehr als eine Box habe und dann nur eine aufklappt und alle anderen zuklappen? Stehe gerade auf dem Schlauch.

    • Geschrieben von: Jan
    • am: 12.10.2016 um 09:28 Uhr

    Kommt drauf an, wie Dein HTML aufgebaut ist.
    Wenn immer abwechselnd input und Box kommen, dann funktioniert es wie oben skizziert, nur mit dem Nachbarselektor (+) statt dem Geschwisterselektor. Im CSS steht also sowas wie:

    input:checked + .box {
    display: block;
    }


    Wenn der HTML-Teil so aufgebaut ist, dass es mit dem Nachbarselektor nicht weiterkommt, verwendet man entsprechende Klassen und/oder IDs. Sieht im CSS dann so aus:

    #toggleBox1:checked ~ .box1,
    #toggleBox2:ckecked ~ .box2 {
    display: block;
    }

    • Geschrieben von: Raum19 Mediengestalter
    • am: 11.11.2016 um 15:31 Uhr

    Hallo zusammen,
    Super Coding, weiter so… denoch habe ich ein Problem in der Einbindung Wordpress Template von Catchthemes.com. Im Beitrag wird nach dem zuklappen, also nach beenden der Div Box </div> der Code <br clear="all"> nicht angenommen, nach einmaligen Öffnen bleibt die Höhe des Inhaltes im Content stehen, nach dem Schliessen, also die Höhe als freier PLatz und dann kommt erst der Footer.
    Beispiel: http://raum19.de/inside/interaktive_webseiten/

    • Geschrieben von: Simon
    • am: 25.11.2016 um 16:04 Uhr

    @rifki: Ich hatte das Problem mit dem Abstand nach dem Zuklappen auch und bei mir hat es geholfen ein overflow: hidden; für den ausgeblendeten Zustand (input:not(:checked) hinzuzufügen.

    • Geschrieben von: M.
    • am: 16.07.2017 um 21:42 Uhr

    Hey,

    habe gerade diesen Code gefunden, und bei mir zum Test in meine Demo Seite (Lokal) eingebaut.

    Danke für den Code, das ist super schlank.

    gruß M.

    • Geschrieben von: Jan
    • am: 27.07.2017 um 10:51 Uhr

    Hallo,

    wie kann ich eine weitere Box hinzufügen? Wenn ich versuche eine Box hinzufügen, wird immer nur die erste geöffnet, egal welche ich anklicke.

    Gruß
    Jan

    • Geschrieben von: Christine
    • am: 11.10.2017 um 21:22 Uhr

    Hallo,
    vielen Dank für den tollen Code. Gibt es eine Möglichkeit mehrere Boxen anzulegen, ohne jede neu bennen zu müssen? Wenn ich mehrere Boxen so einfüge, wird immer die erste geöffnet.

    LG

    Christine

    • Geschrieben von: Jan
    • am: 19.10.2017 um 09:04 Uhr

    @Christine und Jan:
    Schlussendlich müsst Ihr immer für eine eindeutige Zuordnung von input-Element(en) zu Box(en) sorgen. Das kann über die HTML-Struktur und de passenden Selektor oder über die IDs, Klassen, Name o.ä. der Elemente laufen. Was besser passt, muss man im Einzelfall schauen.
    Die Tabs oben (HTML, CSS, Resultat) sind ähnlich gelöst und vielleicht als Beispiel ganz hilfreich.

    • Geschrieben von: Alex
    • am: 13.11.2017 um 22:26 Uhr

    Sehr schöne, einfache und funktionale Lösung. Danke!

    • Geschrieben von: Patrick
    • am: 13.12.2017 um 13:24 Uhr

    Ich hatte das Problem, das sich direkt nach dem letzten schließenden DIV stehender Text im Browser nicht mehr markieren und Links in dem Bereich sich nicht mehr anklicken ließen, dies jedoch nur in der Länge des aus zuklappenden Textes. Das Problem scheint nur aufzutreten, wenn die Checkbox ohne das Attribut checked verwendet wird, also anfänglich zugeklappt.

    Bsp.:


    aufklappen
    zuklappen

    Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
    sed diam nonumy eirmod tempor invidunt ut labore
    et dolore magna aliquyam erat, sed diam voluptua. At vero
    eos et accusam et justo duo dolores et ea rebum.
    Stet clita kasd gubergren, no sea takimata sanctus est
    Lorem ipsum dolor sit amet.
    Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
    sed diam nonumy eirmod tempor invidunt ut labore
    et dolore magna aliquyam erat, sed diam voluptua.


    Hier nicht markierbarer Text und nicht klickbarer Link. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.


    Lösung dafür: (hier height: 0; gegen display:none; tauschen)
    .toggleBox input:not(:checked) ~ div {
    opacity: 0;
    /*height: 0;*/
    display:none;
    }

    • Geschrieben von: Helmut
    • am: 15.12.2017 um 12:09 Uhr

    Ein toller Artikel. Könnte man das Auf- und Zuklappen statt ein-/ausblenden auch animieren?

    • Geschrieben von: Ausprobierer
    • am: 08.02.2018 um 23:47 Uhr

    Hallo,

    echt gut das Aufklappen der Listen. Hat Spaß gemacht!
    Ich habe es für meine Zwecke erweitert und zuerst in einer normalen html Datei gespeichert. Wenn ich diese in Browser aufmache, funktioniert es super. Aber wenn ich die entsprechenden Teile in die Beschreibung einer Kategorie in WordPress eingebe, dann ist die Box an sich zum Klicken da und der Inhalt der Boxen ist ganz zu sehen. Es sieht so aus, als wenn die CSS Anweisungen nicht richtig ausgeführt oder sogar ignoriert wird.

    Wie kann man das Problem lösen? Ich will aber keine JavaScripts oder ähnliches verwenden.

    VG
    Ausprobierer

    • Geschrieben von: Jan
    • am: 09.02.2018 um 10:58 Uhr

    @Helmut: ja, alles was sich per transition ansprechen lässt, kann man hier nutzen.
    @Ausprobierer: Da werden wohl durch Wordpress css-Anweisungen reinkommen, die für Kollisionen sorgen … da bleibt nur zu überprüfen, welche das sind.

    • Geschrieben von: Michael
    • am: 23.04.2018 um 12:23 Uhr

    Herzlichen Dank für den Artikel. Ich war auf der Suche nach einer CSS-Ausklappbox, die ich in einen WP-Shortcode verwandeln konnte. Funktioniert nach etwas Anpassung auch mit mehreren Shortcodes einwandfrei!

    • Geschrieben von: Dieter Glös
    • am: 06.06.2018 um 20:37 Uhr

    Hallo Herr Müller,
    das ist ein ausgezeichneter Code für eine Auf- und Zuklappfunktion per css! Herzlichen Dank und funktioniert bei mir super.
    Gibt es eine Möglichkeit auch per css, wenn die eine Box aufgeklappt wurde und ich die zweite aufklappe, dass dann die erste wieder geschlossen wird?

    Über eine Antwort würde ich mich sehr freuen.
    Beste Grüße
    Dieter Glös

    • Geschrieben von: Jan
    • am: 14.06.2018 um 20:49 Uhr

    @Dieter Glös: Ja, einfach Radio-Buttons statt der Checkboxen nehmen.

    • Geschrieben von: Frank
    • am: 03.10.2019 um 10:14 Uhr

    Vielen Dank für diese kurze und effektive Script!
    Fetten Daumen hoch

    • Geschrieben von: Titania
    • am: 04.08.2021 um 15:32 Uhr

    Sehr schöner code, hat auf anhieb funktioniert. Frage: Ist es möglich, gleichzeitig einen Scroll auszulösen? Ich möchte gern, dass sich nicht nur die Box nach unten öffnet, sondern gleichzeitig der gesamte Inhalt zu einem Anker nach oben springt, um die offene Box vollständig eingeblendet zu haben.

Meine Meinung

Andere Meinung? Fragen? Ergänzungen? Hier ist der Platz dafür. Bitte beachte: Da hier jeder schreiben kann, werden zum Schutz vor Spam und grenzwertigen Inhalten alle Kommentare vor der Veröffentlichung von mir gegengelesen. Deine E-Mailadresse wird ausschließlich für eventuelle Rückfragen und ggf. eine Benachrichtigung bei neuen Antworten verwendet und keinesfalls an Dritte weitergegeben.