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.

Slider, Accordion, Tabs, CSS, Pseudoklasse, Checkbox-Hack

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