Simple jQuery Accordion

von 28 Kommentare

Wie macht man eigentlich..

jsHabt ihr schon mal eine Seite mit so einem netten Accordion-Effekt gesehen und euch gefragt wie das geht? Ich erkläre es euch, schaut euch doch aber erstmal die Demo an, damit ihr wisst, was ich meine.

Wie ihr seht, klappt immer der Bereich auf, auf den geklickt wird. Alle anderen Blöcke bleiben dagegen geschlossen oder schließen sich. Wir bedienen uns hier einfach jQuery und schreiben ein paar Zeilen Code, die den gewünschten Accordion-Effekt realisieren.

HTML-Gerüst

Bevor wir anfangen müssen wir unser HTML aber entsprechend vorbereiten..

1
2
3
4
<h3 class="trigger">Accordion Box 3</h3>
<div class="toggle_container">
	<p>Lorem ipsum dolor sit amet...</p>
</div>

Jeder dieser Blöcke besteht aus einer Überschrift, die später anklickbar sein wird und einem Container, der den eigentlichen Inhalt des Blocks enthält. Wichtig ist, dass wir die Klassen trigger den Überschriften und toggle_container den Containern geben, da später unser jQuery-Code an Hand derer die Aktionen ausführt. Es ist also egal, ob die Überschrift eine h1, h2 oder einfach nur ein div ist, wichtig ist die Klasse und dass danach sofort der Container folgt.

jQuery-Code

Nun zum eigentlichen Code. Vergesst aber nicht, dass ihr vor diesem Script die jQuery-Bibliothek in euer Dokument einbinden müsst! Wie das geht, erfahrt ihr auf der offiziellen jQuery-Seite.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$(document).ready( function() {
	$('.trigger').not('.trigger_active').next('.toggle_container').hide();
	$('.trigger').click( function() {
		var trig = $(this);
		if ( trig.hasClass('trigger_active') ) {
			trig.next('.toggle_container').slideToggle('slow');
			trig.removeClass('trigger_active');
		} else {
			$('.trigger_active').next('.toggle_container').slideToggle('slow');
			$('.trigger_active').removeClass('trigger_active');
			trig.next('.toggle_container').slideToggle('slow');
			trig.addClass('trigger_active');
		};
		return false;
	});
});

Nun zur Erklärung, was da eigentlich abläuft..

  1. Erst nachdem das DOM vollständig geladen ist, greift das Script.
  2. Schließe alle Container, deren Übschrift nicht die Klasse trigger_active hat.
  3. Klickt man auf ein Element der Klasse trigger wird geprüft:
    • Hat es auch die trigger_active-Klasse? Dann mach den darauf folgenden Container zu und entferne die active-Klasse.
    • Ansonsten schließe alle offenen Container und öffne nur den Container, der zur gerade angeklickten Überschrift gehört und gib dieser die active-Klasse.
  4. Es wird kein Wert am Ende der Funktion zurückgegeben (sollte eine Überschrift gleichzeitig ein Link sein).

Zu 2.: Stichwort – Accessibility

Das Schließen der Container würde auch über CSS (display:none) gehen aber was ist, wenn JavaScript nicht aktiviert ist? Dann würden die Leute den Inhalt der Container nicht mehr sehen, weil das Accordion nicht funktioniert.

Styling per CSS

Um das Ganze noch abzurunden, hier der CSS-Code der Demo.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.trigger {
	-moz-border-radius:5px;
	-webkit-border-radius:5px;
	border-radius:5px;
	-moz-box-shadow:0 1px 1px #fff inset;
	-webkit-box-shadow:0 1px 1px #fff inset;
	box-shadow:0 1px 1px #fff inset;
	background:-moz-linear-gradient(center top, #e9e9e9 50%, #ddd 50%);
	background-color:#ddd;
	border:1px solid #ddd;
	color:#888;
	cursor:pointer;
	margin-bottom:5px;
	padding:5px;
	text-shadow:0 1px 0 #fff;
	width:388px;
}
.trigger_active {
	color:#333;
}
.toggle_container {
	padding:5px 10px;
	width:380px;
}

Wenn ihr das Problem habt, dass die Animation nicht flüssig ist sondern abrupt endet, versucht mal der Klasse trigger_container eine feste Breite zu geben. Damit sollte es klappen.

Allerdings ist das natürlich nur ein sehr rudimentäres Aussehen. Wie wäre es zum Beispiel mit einem Plus- oder Minussymbol, damit Benutzer gleich wissen: “Ah, hier kann ich also etwas auf-/zuklappen”? Eurer Kreativität sind hier natürlich keine Grenzen gesetzt. Viel Spaß mit eurem Accordion. :)

Die hier könnten dich auch interessieren

28 Kommentare RSS

Kaloeffel

Bei mir springt es am Ende immer etwas. Als wenn die Fahrt immer eine Bestimmte Zeit lang geht und es dann auf die richtüge größe springt. Denn bei den Kurzen Texten fährt es zu weit und bei dem Langen zu kurz.
Passiert bei mir mit allen Browsern.

Norman

Da wird die Funktion slideToggle("slow") dran schuld sein, die kann man ja vllt mit einer anderen ersetzen.
@Kaloeffel: der Bug wurde soeben behoben.. hing mit der Vergabe von margin zusammen.

Florian Egert

Super Tutorial,

vielen Dank! :)

Eine Frage wie schaffe ich es bei oben genanntem Beispiel, dass der erste Container geöffnet ist, so wie es jetzt ist ist ja alles geschlossen am Anfang.

Norman

Hi Florian,
gute Frage und auch noch einfach zu lösen. Damit der erste Block am Anfang geöffnet ist, musst du der ersten Überschrift einfach die Klasse trigger_active geben und ins Script musst du noch diese Zeile einfügen:

$('.trigger_active').next('.toggle_container').show();

Ausgehend vom Script oben entweder nach Ziele 2 oder vor die Zeile 13.
Danke und viele Grüße!

carsten

Hi Norman,

kannst Du mir erklären, wie man einen bestimmten Container über einen link oder textanker öffnen kann? Gibt es eine Funktion wie: $(‘.selector’).accordion({ navigation: true });

Gruß, Carsten.

P.S. Schönes Blogdesign und klasse Infos. Macht Spaß hier zu lesen ;-)

Mephista

Und wie funktioniert das wenn man statt der horizontalen Navigation lieber eine vertikale Navigation machen möchte?

Vielen Dank für den Tipp!

LG M.

Norman

Hallo Mephista,
das ist leider ein ganz anderer Effekt, das wär mal was für einen eigenen Artikel (danke für die Idee) ;)

Bis es soweit ist, kannst du ja mal nach horizontal jQuery accordion suchen, da findet man ein paar ganz gute Artikel zum Thema. Das sind allerdings meistens Plugins und deswegen etwas umfangreicher. Ich hoffe trotzdem, dass dir das weiterhilft.

Franzi

Hallo Norman,

folgende Situation:

Der User besucht die Seite, der erste Container ist geöffnet, die anderen geschlossen. Er klickt auf den zweiten Link, der erste Container schließt sich, der zweite öffnet sich. Soweit ok. Dann jedoch klickt der User wieder auf den zweiten Link, dieser schließt sich und nun ist garnichts mehr geöffnet.
Das möchte ich vermeiden indem wieder der erste Container geöffnet wird.

Ist das möglich?

Gruß,

Franzi

Norman

Hallo Constantin,
das ist bereits der Fall! Denn die Container werden ja erst mit JS geschlossen. Hat der Nutzer JS deaktiviert, bleiben die Container einfach offen, testen kannst du das in der Demo.
Bitte und viele Grüße,
Norman

Phil

Hi Norman,

Erst mal Gratulation zu Deinem Blog, finde ich sehr gelungen :)

Das Skript ist absolute Klasse und passt super als Ergänzung auf Seiten mit sehr viel Content!

Allerdings habe ich ein kleines Problem damit die erste Container Box geöffnet darzustellen. Ich weiss dass die Frage bereits gestellt wurde, aber irgendwie funktioniert das bei mir nicht so ganz. (vielleicht ein doofer Fehler beim Markup oder im JS?)

Ich arbeite gerade an einem Redesign und habe auch eine Demoseite hochgeladen: http://www.kipperdesign.ch/sct_redesign/

Leider ist mein Wissen über Javascript noch im Anfängerstadium und ich wollte fragen ob es eventuell möglich wäre mir in dem Fall zu helfen? Würde mich sehr freuen.

Freundliche Grüsse,

Phil

Phil

Hi Norman,

danke für die promte Antwort! Ich habe zu der “trigger_active”-Klasse noch eine “trigger”-Klasse hinzugefügt. Nun sieht es zu Anfang zwar korrekt aus, ist aber nicht klickbar und verfällt wenn man eine andere Rubrik öffnen möchte :(
Vielleicht hast du eine Idee?

Liebe Grüsse,
Phil

Phil

Und auf einmal klappt es! Ich habe keine Ahnung was ich geändert habe aber ich ziehe dementsprechend meine vorherige Frage zurück. Herzlichen Dank für die tolle und schnelle Unterstützung.

Freundliche Grüsse,
Phil

vanhey

hi danke für dein tutorial – funktioniert am besten von allen. bin leider nicht so versiert in .js – aber vielleicht hast du eine idee wie man eine verschachtelte acc anhand deines scripts machen kann? habe die funktion pragmatischer weisse einfach kopiert und dupliziert mit neuen klassen – das problem ist nur das die unter acc immer gleichzeitig aufgehen, also wenn zwei vorhanden – öffnen sich beide – oder aber ich klicke nr. eins und nr.zwei öffnet sich – hast du einen tip? … und danke nochmal für den super beitrag.

Michael

Soweit finde ich das script wirklich sehr gut und vor allem verglichen mit vielen anderen sehr überschaubar und kurz…daher *TOP*!!

Nur ein Problem hat das ganze…undzwar die feste Höhe…wenn ich eine feste Höhe benenne, dann ist es ein harmonischer Ablauf…sobald ich die Höhe automatisch bemessen lasse hackt es ab..es läuft an, aber hackt am schluss ab…
Problem ist…für jede Box dieselbe Höhe angeben ist doch nicht sinngemäß..nicht jede Box enthält den gleichen Inhalt…und für jede Box ne eigene ID und ins script einbinden ist sehr umständlich…

Ich habe einiges probiert, komme aber nicht auf die Lösung..warum hackt es bei ner automatischen Höhe??

Norman

@Michael: Hm eigentlich musst du nur eine fester Breite vergeben, die Höhe sollte immer automatisch sein.. siehe auch die Demo, dort ist nur die Breite fest.

Denis

Hey,
was muss ich denn ändern, damit der erste Container schon offen ist, wenn die seite betreten wird? Die anderen sind zu. Der erste Container soll erst zugemacht werden, wenn ich einen anderen aufmache.

Danke!

Niklas

Schönes Script. Ich würde dem slideToggle anstatt des Wertes slow allerdings einen Zahlenwert geben z.B. slideToggle(“200″) für 200 Millisekunden. Dadurch ließen sich bei mir schon des öfteren hackelige Animationen vermeiden. Nichts desto trotz ein leicht Verständlicher Lösungsweg der mir sehr gut auf die Sprünge geholfen hat. Danke dafür :)

Jennifer

Hallo Norman,

ich habe ein Problem was bereits weiter oben bereits genannt worden ist.
Der Text fährt aus und dann sofort wieder zu so, dass man nicht die chance hat diesen komplett zu lesen. Ich verstehe nicht ganz was ich ändern kann damit die Animation quasi am Ende stehen bleibt.

Danke schon mal für deine Hilfe und viele Grüße

Norman

Hi Jennifer,
hast du vielleicht ein konkretes Beispiel, dass du mir zeigen kannst? Kann mir das Verhalten gerade nicht erklären..
Danke und Grüße!

Altilux

@Norman

Ich habe das gleiche Problem wie Jennifer.

Ich habe dem ersten Container in der Überschrift “trigger_active” in der class hinzugefügt, wie du es weiter oben (klick) gesagt hast.

Es liegt meines Erachtens an dem style “display”, der durch das Script dem anzuzeigenden Container verleiht. Angezeigt: “display:block”, Nicht angezeigt “display:none”. Leider konnte ich die Eigenschaft nicht korrigieren, da diese stets vom Script überschrieben wird.

Ich brauche es so, dass beim 1. Seitenaufruf der 1. Container geöffnet ist und dass durch klicken von “weiter” der zweite Container geöffnet wird und dabei der erste wieder geschlossen wird. Das kann ich durch POST-Varaiblen lösen, doch eben nur, wenn ich weiß, wie ich das Script anpassen muss, damit der von mir gewünschte Container beim Seitenaufruf geöffnet ist.

Sonst nen klasse Script inkl. Beschreibung *THUMBS UP*

Chris

Martin

Hallo, vielen Dank für das Script.

Wenn man mit flexiblen Höhen und breiten arbeiten möchte kann man folgendes Script nutzen um den Boxen eine Breite zu geben, und somit das unschöne “flackern” verhindern.

1
2
3
$('.toggle_container').each(function() {
		$(this).width($(this).innerWidth()).hide();
});

einfach damit diese Zeile ersetzen:

1
$('.trigger').not('.trigger_active').next('.toggle_container').hide();

Dann müsste es klappen. Habe mein Script etwas anders aufgebaut, aber iich denke das sollte passen.

VG

Kommentieren