Kalender, Warenkörbe, Galerien, Dateiexplorer und Online-Bibliotheken sind einige Situationen, in denen auswählbare Elemente in Grids (d.h. quadratischen Gittern) angezeigt werden. Wissen Sie, sogar diese Sicherheitsüberprüfungen, die Sie bitten, alle Bilder mit Zebrastreifen oder was auch immer auszuwählen.

Ich habe eine nette Möglichkeit gefunden, auswählbare Optionen in einem Grid anzuzeigen. Nein, nicht das reCAPTCHA neu erstellen, sondern einfach mehrere Elemente auswählen können. Und wenn zwei oder mehr angrenzende Elemente ausgewählt sind, können wir clevere :nth-of-type Kombinatoren, Pseudoelemente und die :checked Pseudoklasse verwenden, um sie so zu stylen, dass sie zusammen gruppiert aussehen.
Die gesamte Idee von Kombinatoren und Pseudoelementen, um die abgerundeten Checkboxen zu erhalten, stammt aus einem früheren Artikel, den ich geschrieben habe. Es war ein einfaches Design mit einer Spalte
Dieses Mal wird der Abrundungseffekt jedoch auf Elemente entlang der vertikalen und horizontalen Achsen in einem Grid angewendet. Sie müssen meinen letzten Artikel über das Stylen von Checkboxen nicht gelesen haben, da ich hier alles abdecke, was Sie wissen müssen. Aber wenn Sie an einer schlankeren Version dessen interessiert sind, was wir in diesem Artikel tun, dann lohnt sich dieser.
Bevor wir anfangen...
Es ist hilfreich, sich ein paar Dinge zu merken. Ich verwende zum Beispiel statisches HTML und CSS in meiner Demo zur Vereinfachung. Abhängig von Ihrer Anwendung müssen Sie das Grid und die darin enthaltenen Elemente möglicherweise dynamisch generieren. Ich lasse praktische Barrierefreiheitsprüfungen aus, um mich auf den Effekt zu konzentrieren, aber Sie würden dies in einer Produktionsumgebung definitiv berücksichtigen.
Außerdem verwende ich CSS Grid für das Layout. Das würde ich auch empfehlen, aber es ist natürlich nur eine persönliche Präferenz und Ihre Erfahrungen können variieren. Für mich ermöglicht die Verwendung von Grid, einfach Geschwisterselektoren zu verwenden, um die ::before und ::after Pseudoelemente eines Elements anzusprechen.
Daher, egal welchen Layout-Standard Sie in Ihrer Anwendung verwenden möchten, stellen Sie sicher, dass die Pseudoelemente immer noch in CSS angesprochen werden können und dass das Layout über verschiedene Browser und Bildschirme hinweg intakt bleibt.
Legen wir jetzt los
Wie Sie vielleicht in der früheren Demo bemerkt haben, ändert das Aktivieren und Deaktivieren eines Kontrollkästchens das Design der Felder, je nach Auswahlzustand der anderen Kontrollkästchen um sie herum. Dies ist möglich, weil ich jedes Feld mithilfe der Pseudoelemente seiner benachbarten Elemente gestylt habe und nicht des Elements selbst.
Die folgende Abbildung zeigt, wie die ::before Pseudoelemente von Feldern in jeder *Spalte* (außer der ersten Spalte) die Felder links davon überlappen, und wie die ::after Pseudoelemente von Feldern in jeder *Reihe* (außer der ersten Reihe) die Felder darüber überlappen.

Hier ist der Basissourcecode
Das Markup ist ziemlich einfach
<main>
<input type=checkbox>
<input type=checkbox>
<input type=checkbox>
<!-- more boxes -->
</main>
In der anfänglichen CSS passiert etwas mehr. Aber zuerst das Grid selbst
/* The grid */
main {
display: grid;
grid: repeat(5, 60px) / repeat(4, 85px);
align-items: center;
justify-items: center;
margin: 0;
}
Das ist ein Grid aus fünf Zeilen und vier Spalten, das Kontrollkästchen enthält. Ich habe mich entschieden, das Standardaussehen der Kontrollkästchen zu entfernen und ihnen dann meinen eigenen hellgrauen Hintergrund und super abgerundete Ränder zu geben
/* all checkboxes */
input {
-webkit-appearance: none;
appearance: none;
background: #ddd;
border-radius: 20px;
cursor: pointer;
display: grid;
height: 40px;
width: 60px;
margin: 0;
}
Beachten Sie auch, dass die Kontrollkästchen selbst Grids sind. Das ist entscheidend für die Platzierung ihrer ::before und ::after Pseudoelemente. Davon sprechen wir jetzt
/* pseudo-elements except for the first column and first row */
input:not(:nth-of-type(4n+1))::before,
input:nth-of-type(n+5)::after {
content: '';
border-radius: 20px;
grid-area: 1 / 1;
pointer-events: none;
}
Wir wählen nur die Pseudoelemente von Kontrollkästchen aus, die sich nicht in der ersten Spalte oder der ersten Reihe des Grids befinden. input:not(:nth-of-type(4n+1)) beginnt beim ersten Kontrollkästchen und wählt dann das ::before jedes vierten Elements von dort aus. Aber beachten Sie, dass wir :not() sagen, also was wir wirklich tun, ist, das ::before Pseudoelement jedes vierten Kontrollkästchens zu *überspringen*, beginnend beim ersten. Dann wenden wir Stile auf das ::after Pseudoelement jedes Kontrollkästchens ab dem fünften an.
Jetzt können wir sowohl die ::before als auch die ::after Pseudoelemente für jedes Kontrollkästchen stylen, das sich nicht in der ersten Spalte oder Reihe des Grids befindet, sodass sie nach links oder oben bewegt werden und standardmäßig verborgen sind.
/* pseudo-elements other than the first column */
input:not(:nth-of-type(4n+1))::before {
transform: translatex(-85px);
}
/* pseudo-elements other than the first row */
input:nth-of-type(n+5)::after {
transform: translatey(-60px);
}
Styling des :checked Zustands
Nun kommt das Styling der Kontrollkästchen, wenn sie sich im :checked Zustand befinden. Geben wir ihnen zuerst eine Farbe, sagen wir einen limegreen Hintergrund
input:checked { background: limegreen; }
Ein ausgewähltes Feld sollte in der Lage sein, alle seine benachbarten ausgewählten Felder neu zu stylen. Mit anderen Worten, wenn wir das elfte Kontrollkästchen im Grid auswählen, sollten wir auch die Felder darüber, darunter, links und rechts um sie herum stylen können.

Dies geschieht durch Ansprechen der richtigen Pseudoelemente. Wie machen wir das? Nun, das hängt von der tatsächlichen Anzahl der Spalten im Grid ab. Hier ist die CSS, wenn zwei benachbarte Felder in einem 5⨉4 Grid ausgewählt sind
/* a checked box's right borders (if the element to its right is checked) */
input:not(:nth-of-type(4n)):checked + input:checked::before {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
background: limegreen;
}
/* a checked box's bottom borders (if the element below is checked) */
input:nth-last-of-type(n+5):checked + * + * + * + input:checked::after {
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
background: limegreen;
}
/* a checked box's adjacent (right side) checked box's left borders */
input:not(:nth-of-type(4n)):checked + input:checked + input::before {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
background: limegreen;
}
/* a checked box's adjacent (below) checked box's top borders */
input:not(:nth-of-type(4n)):checked + * + * + * + input:checked + input::before {
border-top-left-radius: 0;
border-top-right-radius: 0;
background: limegreen;
}
Wenn Sie möchten, können Sie den obigen Code auch dynamisch generieren. Bei einem typischen Grid, wie z.B. einer Bildergalerie, ist die Anzahl der Spalten klein und die Anzahl der Elemente wahrscheinlich festgelegt, während die Reihen zunehmen können. Besonders wenn für mobile Bildschirme konzipiert. Deshalb ist dieser Ansatz immer noch eine effiziente Methode. Wenn Ihre Anwendung aus irgendeinem Grund begrenzte Reihen und sich erweiternde Spalten hat, dann erwägen Sie, das Grid seitwärts zu drehen, denn bei einer Stream von Elementen ordnet CSS Grid sie von links nach rechts und von oben nach unten an (d.h. zeilenweise).
Wir müssen auch Stile für die letzten Kontrollkästchen im Grid hinzufügen – sie werden nicht alle von Pseudoelementen abgedeckt, da sie die letzten Elemente auf jeder Achse sind.
/* a checked box's (in last column) left borders */
input:nth-of-type(4n-1):checked + input:checked {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
/* a checked box's (in last column) adjacent (below) checked box's top borders */
input:nth-of-type(4n):checked + * + * + * + input:checked {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
Das sind einige knifflige Selektoren! Der erste...
input:nth-of-type(4n-1):checked + input:checked
...bedeutet im Grunde dies
Ein ausgewähltes
<input>Element neben einem ausgewählten<input>in der vorletzten Spalte.
Und die nth-of-type Berechnung erfolgt wie folgt
4(0) - 1 = no match
4(1) - 1 = 3rd item
4(2) - 1 = 7th item
4(3) - 1 = 11th item
etc.
Wir beginnen also beim dritten Kontrollkästchen und wählen von dort jedes vierte aus. Und wenn ein Kontrollkästchen in dieser Sequenz ausgewählt ist, dann stylen wir auch die benachbarten Kontrollkästchen, wenn diese ebenfalls ausgewählt sind.
Und diese Zeile
input:nth-of-type(4n):checked + * + * + * + input:checked
Bedeutet dies
Ein
<input>Element, das ausgewählt ist, ist direkt benachbart zu einem Element, das direkt benachbart ist zu einem weiteren Element, das ebenfalls direkt benachbart ist zu einem weiteren Element, das wiederum direkt benachbart ist zu einem<input>Element, das sich in einem ausgewählten Zustand befindet.
Das bedeutet, wir wählen jedes vierte ausgewählte Kontrollkästchen aus. Und wenn ein Kontrollkästchen in dieser Sequenz ausgewählt ist, dann stylen wir das nächste vierte Kontrollkästchen von diesem Kontrollkästchen aus, wenn dieses ebenfalls ausgewählt ist.
Praktische Anwendung
Was wir gerade betrachtet haben, ist das allgemeine Prinzip und die Logik hinter dem Design. Wie nützlich es in Ihrer Anwendung ist, hängt wieder vom Grid-Design ab.
Ich habe abgerundete Ränder verwendet, aber Sie können auch andere Formen ausprobieren oder sogar mit Hintergrundeffekten experimentieren (Temani hat Ideen für Sie). Jetzt, da Sie die Formel kennen, ist der Rest Ihrer Vorstellungskraft überlassen.
Hier ist ein Beispiel, wie es in einem einfachen Kalender aussehen könnte
Auch dies ist lediglich ein grober Prototyp mit statischem Markup. Und es gäbe viele, viele Barrierefreiheitsaspekte zu berücksichtigen in einer Kalenderfunktion.
Das war's! Ziemlich raffiniert, oder? Ich meine, es gibt nichts wirklich "Neues" an dem, was passiert. Aber es ist ein gutes Beispiel für das *Auswählen von Dingen* in CSS. Wenn wir fortgeschrittene Auswahltechniken mit Kombinatoren und Pseudoelementen beherrschen, dann können unsere Styling-Möglichkeiten weit über das Stylen eines einzelnen Elements hinausgehen – wie wir gesehen haben, können wir Elemente bedingt auf Basis des Zustands eines anderen Elements stylen.
Das ist ein cooler CSS-Trick. Danke!
+1. Raffinierte Idee und Umsetzung!
Können wir komplexe Zahlen und Matrizen verwenden, und wäre es dann viel einfacher niederzuschreiben?