Grid-Accordion mit jQuery

Avatar of Chris Coyier
Chris Coyier am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Akkordeons sind ein UI-Muster, bei dem man auf einen Titel klickt (in einem vertikalen Stapel von Titeln) und sich darunter ein Inhaltsbereich öffnet. Typischerweise schließen sich alle anderen geöffneten Bereiche, wenn sich ein neuer öffnet. Sie sind ein cleverer und ansprechender Mechanismus, um viele Informationen auf kleinem Raum unterzubringen.

Basis-Akkordeon von jQuery UI

Eine Möglichkeit, ein Akkordeon zu betrachten, ist wie eine eingeklappte einzelne Spalte einer Tabelle. Ich habe kürzlich eine Seite für eine Kunden-Website erstellt, bei der die von ihnen bereitgestellten Informationen am besten in einer Tabelle dargestellt werden konnten. Aber es waren zu viele Informationen, um sie auf einmal anzuzeigen. Ich dachte, das wäre visuell überwältigend gewesen. Ich dachte auch, dass die Leute, die diese Seite besuchen, wahrscheinlich sofort wissen würden, was sie brauchen, daher schien es ziemlich vernünftig, sie einmal klicken zu lassen, um es zu erhalten. Also, eine Tabelle von Akkordeons!

Eine weitere Überlegung bei dieser Tabelle, die ich gerade erstellt habe, ist, dass es genügend Spalten gab, dass jede einzelne Spalte (wenn sie in dem verfügbaren Platz gleich breit gewesen wären) nicht sehr breit war, vielleicht 150 Pixel. Einige dieser Zellen enthielten mehrere Textabsätze. Eine 150 Pixel breite Zelle mit mehreren Textabsätzen wäre unglücklich hoch. Daher wurde das Grid-Akkordeon geboren!

Das Grid-Akkordeon funktioniert nach der gleichen Theorie wie die meisten anderen Akkordeons. Nur eine Zelle ist gleichzeitig geöffnet. Das Wichtigste ist, dass sich die Spalte der aktuell geöffneten Zelle auf eine angemessene Lesebreite erweitert.

Sie können das Beispiel am Ende dieses Artikels ansehen und herunterladen. Ich werde nun einige der wichtigen Teile durchgehen.

HTML: Klassische Verwendung der Definitionsliste

Akkordeons sind perfekte semantische Beispiele für Definitionslisten. Eine kurze Wiederholung davon

<dl>
   <dt>Title</dt>
   <dd>Information about that title here</dd>
   <dt>Another Title</dt>
   <dd>Information about that other title here</dd>
</dl>

Unser Grid-Akkordeon wird aus divs bestehen, die in einer horizontalen Reihe gefloatet sind. Jedes div enthält den Titel der Spalte und ein Bild, sowie – am wichtigsten – die Definitionsliste selbst. Beispiel für eines dieser divs

<div class="info-col">

	<h2>Batman</h2>
	
	<a class="image batman" href="http://jprart.deviantart.com/">View Image</a>
	
	<dl>
	  <dt>Super Power</dt>
	  <dd>Consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</dd>
	  <dt>Costume</dt>
	  <dd>Consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</dd>
	  <dt>Morality</dt>
	  <dd>Consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</dd>
	  <dt>Sidekicks</dt>
	  <dd>Consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</dd>
	  <dt>Vehicles</dt>
	  <dd>Consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</dd>
	  <dt>Weaknesses</dt>
	  <dd>Consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</dd>
	</dl>

</div>

CSS: Versuch, barrierefrei zu bleiben

Der Großteil des CSS ist nur eine einfache Einrichtung und nicht wirklich hier abgedeckt (die vollständige CSS-Datei finden Sie hier).

Ein Aspekt, der es jedoch wert ist, behandelt zu werden, ist die Barrierefreiheit. Wir müssen standardmäßig alle Informationsbereiche der Tabelle "verstecken". Eine Möglichkeit, dies zu tun, wäre, dieddElemente im CSS auf display: none; zu setzen. Dies ist jedoch ein ernsthaftes Problem für die Barrierefreiheit, da viele Screenreader diesem CSS gehorchen und diese Informationen vollständig entfernen.

Stattdessen können wir die Zellen "verstecken", indem wir sie einfach aus dem Browserfenster schieben.

dd { position: absolute; top: -9999px; left: -9999px; }

Dies ist eine klassische Technik. Tatsächlich ist es ziemlich üblich, genau diese CSS-Eigenschaften und Werte mit einem Utility-Klassennamen wie diesem zu sehen.

.screen-reader-text { position: absolute; top: -9999px; left: -9999px; }

Wir haben jedoch noch eine weitere Sorge. Wir werden einige jQuery-Animationen verwenden, um die Info-Zellen nach oben und unten zu schieben. Wir können sie also nicht für normale Betrachter aus der Seite herausschneiden. Wir verschieben die Zellen zurück, wenn das JavaScript zuerst ausgeführt wird, und lassen das JavaScript sie dann verstecken.

Die Funktion slideDown von jQuery funktioniert am besten, wenn sie bereits weiß, wie hoch das Element vor dem Schließen oder Verstecken war, damit sie sich sanft auf die ursprüngliche Höhe zurückanimieren kann. Wenn wir display: none; im CSS verwenden würden, wüsste diese Funktion nicht, wie hoch diese Zellen sein sollen. Wenn wir sie stattdessen aus der Seite herausschieben, wird die ursprüngliche Höhe berechnet, was die Animation so reibungslos wie möglich hält. Wir müssen nur sicherstellen, dass die Zelle auf ihre "volle" Breite eingestellt ist, damit die Höhe bei der Breite berechnet wird, die die Zelle haben wird, wenn sie sichtbar ist.

dd { width: 299px; position: absolute; left: -9999px; top: -9999px; }

Zu diesem Zeitpunkt haben wir eine barrierefreie Informationsseite, sodass Screenreader alles erhalten sollten, was sie brauchen, und normale Benutzer ein reibungslos funktionierendes System haben. Eine Sache, die jedoch nicht vollständig berücksichtigt wird, ist einfach die Deaktivierung von JavaScript. In diesem Szenario sind die Informationszellen immer noch durch CSS versteckt. Persönlich bin ich viel mehr besorgt über die Barrierefreiheit als über Leute, die mit deaktiviertem JavaScript und einer Fackel herumsurfen. Wenn Sie es jedoch sind, können Sie entweder 1) eine <noscript>-Nachricht einfügen oder 2) das CSS-Verstecken entfernen und einfach einen kurzen Inhalts-Flash zulassen, bevor das JavaScript die Zellen versteckt.

CSS: Spaß mit CSS3

Der CSS3-Pseudo-Klassen-Selektor :nth-of-type ist besonders nützlich bei Definitionslisten. Da die dt- und dd-Elemente sich abwechseln und sogar wiederholt oder in beliebiger Reihenfolge auftreten können, wäre :nth-child eine nicht wartbare Option. Färben wir die Zellen der Tabelle mit :nth-of-type.

dt:nth-of-type(1) { background: #b44835; }
dd:nth-of-type(1) { background: #b44835; }

dt:nth-of-type(2) { background: #ff7d3e; }
dd:nth-of-type(2) { background: #ff7d3e; }

dt:nth-of-type(3) { background: #ffb03b; }
dd:nth-of-type(3) { background: #ffb03b; }

dt:nth-of-type(4) { background: #c2a25c; }
dd:nth-of-type(4) { background: #c2a25c; }

dt:nth-of-type(5) { background: #4c443c; }
dd:nth-of-type(5) { background: #4c443c; }

dt:nth-of-type(6) { background: #656b60; }
dd:nth-of-type(6) { background: #656b60; }

Für die "rabble-rabble-IE-kompatible" Menge können Sie gerne zusätzliche Klassennamen zu den Zellen hinzufügen und Ihre Farbgebung mit diesen Hooks vornehmen.

Eines der Flair-Elemente, das wir hinzufügen werden, ist das Hervorheben der aktuellen Spalte. Der Klassenname "curCol" wird nach Bedarf über JavaScript angewendet und entfernt. Die aktuelle Spalte erhält einen Schatten um sich herum, was natürlich die perfekte Anwendung für box-shadow ist.

.curCol { -moz-box-shadow: 0 0 10px rgba(0,0,0,0.2); -webkit-box-shadow: 0 0 10px rgba(0,0,0,0.2); z-index: 1; position: relative; }

Als ich damit spielte, habe ich ursprünglich versucht, einige Transformationen zu verwenden, um die Größe der aktuellen Spalte zu skalieren. Letztendlich gefiel mir das Aussehen nicht (eins-Pixel-Linien sehen beim Skalieren schrecklich aus). Ich mochte die Schatten viel mehr, aber ich stellte fest, dass der rechte Rand des Schattens vom nächsten Spalte abgeschnitten wurde. Das lag daran, dass diese nächste Spalte in der vertikalen Stapelreihenfolge leicht über der aktuellen lag. Daher hat die curCol-Klasse z-index und relative Positionierung, um sicherzustellen, dass sie über den anderen liegt.

Zufällig habe ich auch entdeckt, dass die transform-Eigenschaft das Problem gelöst hat. Da die Einstellung von -moz-transform: scale(1); (was etwas auf 100% skaliert, oder im Grunde nichts mit unskalierten Elementen macht) auch funktionierte, indem der Schatten sichtbar gemacht wurde. Mit anderen Worten: die Verwendung von Transformationen auf Elementen beeinflusst deren vertikale Stapelreihenfolge. Ich bin mir nur noch nicht ganz sicher, wie das alles genau funktioniert.

jQuery JavaScript

Auch hier werde ich nicht jede Zeile abdecken (Sie können die vollständige Datei hier sehen). Hier ist jedoch die logische Struktur:

  1. Wenn auf eine <dt>-Element geklickt wird...
  2. Wenn es die aktuell aktive Zelle ist, tue nichts
  3. Andernfalls...
  4. Schließe alle geöffneten Zellen
  5. Schrumpfe den alten Titel
  6. Vergrößere den neuen Titel
  7. Öffne die neue Zelle
  8. Markiere die aktuelle Spalte
  9. Stelle sicher, dass die aktuelle Spalte erweitert und die anderen geschrumpft sind

Ein paar interessante Dinge...

Ich hätte normalerweise die .live()-Funktion verwendet, um die Klicks auf die dt-Elemente zu behandeln. Aber der neumodische Hipster-Weg, dies in jQuery zu handhaben, ist die Verwendung von .delegate().

$("#page-wrap").delegate("dt", "click", function() {
  // do stuff
}

Wo live das gesamte Dokument auf Klicks überwachen müsste, beschränkt delegate diese Überwachung nur auf den page-wrap, was effizienter ist.

Ich habe das Doug Neiner gezeigt, und er schlug auch vor, dass ein Klick auf die Fotos in jeder Spalte nur die Spalte öffnen würde. Dann, wenn erneut geklickt wird, würden sie tatsächlich zur Website des Künstlers gehen (wofür der href jedes Bildes verlinkt). Der Trick hierbei war, die Standardaktion (zum Link gehen) beim Klicken auf ein Bild zu verhindern, wenn es nicht die aktuelle Spalte ist. Stattdessen wird der Klick auf den ersten Titel in dieser Spalte umgeleitet (der ihn öffnet). Wir können dafür wieder delegate verwenden.

$("#page-wrap").delegate("a.image","click", function(e) { 
    
    if ( !$(this).parent().hasClass("curCol") ) {         
        e.preventDefault(); 
        $(this).next().find('dt:first').click(); 
    } 
    
});

Demo und Download

Demo anzeigen   Dateien herunterladen

Bis ich ein gutes Lizenzsystem entwickelt habe... nur eine Erinnerung, dass jedes herunterladbare Beispiel wie dieses auf dieser Website von Ihnen beliebig verwendet werden kann. Vorzugsweise verwenden Sie es in großen Unternehmensprojekten und verdienen viel Geld. Oder zeigen Sie es Ihren Freunden und sagen Sie ihnen, dass Sie es getan haben, damit sie denken, Sie seien großartig.