Vor einiger Zeit teilte Chris dieses schöne sechseckige Raster. Und wie der Name schon sagt, verwendet es – warten Sie mal – CSS Grid für dieses Layout. Das ist ein cleverer Trick! Die Kombination aus Grid-Spalten, Grid-Abständen und kreativen Ausschnitten ergibt das Endergebnis.
Etwas Ähnliches könnte man auch mit Flexbox erreichen. Aber ich bin hier, um unseren alten Freund float wiederzubeleben, um dieselbe Art von komplexem und responsivem Layout zu erstellen – aber mit weniger Komplexität und ohne eine einzige Media Query.
Ich weiß, es ist schwer zu glauben. Beginnen wir also mit einer funktionierenden Demo
Dies ist ein vollkommen responsives Sechseckraster, das ohne Media Queries, JavaScript oder eine Menge hacky CSS erstellt wurde. Vergrößern oder verkleinern Sie den Demo-Bildschirm und sehen Sie die Magie. Zusätzlich zur Responsivität skaliert das Raster auch. Wir können zum Beispiel mehr Sechsecke hinzufügen, indem wir mehr Divs einfügen, und sowohl die Größe als auch den Abstand mit CSS-Variablen steuern.
Cool, oder? Und das ist nur ein Beispiel unter vielen Rastern, die wir auf dieselbe Weise erstellen werden.
Ein Gitter aus Sechsecken erstellen
Zuerst erstellen wir unsere Sechseckform. Diese Aufgabe ist mit clip-path recht einfach. Wir betrachten eine Variable S, die die Dimension unseres Elements definiert. Bennett Feely’s Clippy ist ein großartiger Online-Generator für Clipping-Pfade.

clip-pathJedes Sechseck ist ein inline-block-Element. Die Markierung könnte so aussehen
<div class="main">
<div class="container">
<div></div>
<div></div>
<div></div>
<!--etc. -->
</div>
</div>
…und das CSS
.main {
display: flex; /* we will talk about this later ... */
--s: 100px; /* size */
--m: 4px; /* margin */
}
.container {
font-size: 0; /* disable white space between inline block element */
}
.container div {
width: var(--s);
margin: var(--m);
height: calc(var(--s) * 1.1547);
display: inline-block;
font-size: initial; /* we reset the font-size if we want to add some content */
clip-path: polygon(0% 25%, 0% 75%, 50% 100%, 100% 75%, 100% 25%, 50% 0%);
}
Bisher nichts Komplexes. Wir haben ein Hauptelement, das einen Container enthält, der wiederum die Sechsecke enthält. Da wir es mit inline-block zu tun haben, müssen wir das übliche Problem mit Leerzeichen bekämpfen (mit dem font-size-Trick) und wir berücksichtigen etwas Rand (definiert durch die Variable M), um den Abstand zu steuern.

Hier ist das bisherige Ergebnis

Jede zweite Reihe benötigt einen negativen Versatz, damit sich die Reihen überlappen, anstatt direkt aufeinander zu stapeln. Dieser Versatz wird 25% der Elementhöhe entsprechen (siehe Abbildung 1). Wir wenden diesen Versatz auf margin-bottom an, um Folgendes zu erhalten
.container div {
width: var(--s);
margin: var(--m);
height: calc(var(--s) * 1.1547);
display: inline-block;
font-size: initial;
clip-path: polygon(0% 25%, 0% 75%, 50% 100%, 100% 75%, 100% 25%, 50% 0%);
margin-bottom: calc(var(--m) - var(--s) * 0.2886); /* some negative margin to create overlap */
}
…und das Ergebnis wird

Jetzt kommt der eigentliche Trick: Wie können wir die zweite Reihe verschieben, um ein perfektes sechseckiges Gitter zu erhalten? Wir haben die Dinge bereits so weit zusammengepresst, dass sich die Reihen vertikal überlappen, aber was wir brauchen, ist, jede zweite Reihe nach rechts zu schieben, damit sich die Sechsecke staffeln und nicht überlappen. Hier kommen float und shape-outside ins Spiel.
Haben Sie sich gefragt, warum wir ein .main-Element haben, das unseren Container umschließt und display: flex hat? Dieses Div ist auch Teil des Tricks. In einem früheren Artikel habe ich float verwendet und diesen Flexbox-Container benötigt, um height: 100% verwenden zu können. Das Gleiche werde ich hier tun.
.container::before {
content: "";
width: calc(var(--s)/2 + var(--m));
float: left;
height: 100%;
}
Ich verwende das Pseudo-Element container::before, um ein Float-Element zu erstellen, das die gesamte Höhe am linken Rand des Gitters einnimmt und eine Breite von der Hälfte eines Sechsecks (plus seines Randes) hat. Das Ergebnis ist:

.container::before.Jetzt können wir uns shape-outside zuwenden. Machen wir eine kurze Wiederholung, was es tut. Robin definiert es schön im CSS-Tricks Almanac. MDN beschreibt es ebenfalls schön
Die CSS-Eigenschaft
Hervorhebung von mirshape-outsidedefiniert eine Form – die nicht rechteckig sein kann –, um die sich benachbarte Inline-Inhalte wickeln. Standardmäßig wickeln sich Inline-Inhalte um ihre Margin-Box;shape-outsidebietet eine Möglichkeit, dieses Umwickeln anzupassen, sodass Text um komplexe Objekte statt um einfache Boxen gewickelt werden kann.
Beachten Sie „Inline-Inhalte“ in der Definition. Das erklärt genau, warum die Sechsecke inline-block-Elemente sein müssen. Aber um zu verstehen, welche Art von Form wir brauchen, zoomen wir in das Muster.

Das Coole an shape-outside ist, dass es tatsächlich mit Verläufen funktioniert. Aber welche Art von Verlauf passt zu unserer Situation?
Wenn wir zum Beispiel 10 Reihen von Sechsecken haben, müssen wir nur jede *gerade* Reihe verschieben. Anders ausgedrückt: Wir müssen jede zweite Reihe verschieben, also brauchen wir eine Art Wiederholung – perfekt für einen wiederholten Verlauf!
Wir erstellen einen Verlauf mit zwei Farben
- Eine transparente, um den „freien Raum“ zu schaffen und gleichzeitig die erste Reihe an Ort und Stelle zu halten (illustriert durch den blauen Pfeil oben).
- Eine opakere Farbe, um die zweite Reihe nach rechts zu verschieben, damit sich die Sechsecke nicht direkt übereinander stapeln (illustriert durch den grünen Pfeil).
Unser Wert für shape-outside wird so aussehen
shape-outside: repeating-linear-gradient(#0000 0 A, #000 0 B); /* #0000 = transparent */
Nun finden wir die Werte für A und B. B wird einfach gleich der Höhe von zwei Reihen sein, da unsere Logik alle zwei Reihen wiederholen muss.
Die Höhe von zwei Reihen ist gleich der Höhe von zwei Sechsecken (einschließlich ihrer Ränder), abzüglich zweimal der Überlappung (2*Höhe + 4*M - 2*Höhe*25% = 1,5*Höhe + 4*M). Oder, in CSS mit calc() ausgedrückt
calc(1.732 * var(--s) + 4 * var(--m))
Das ist viel! Also halten wir das alles in einer benutzerdefinierten CSS-Eigenschaft, F.
Der Wert von A (definiert durch den blauen Pfeil in der vorherigen Abbildung) muss mindestens so groß sein wie die Größe eines Sechsecks, kann aber auch größer sein. Um die zweite Reihe nach rechts zu verschieben, benötigen wir ein paar Pixel opake Farbe, daher kann A einfach gleich B - Xpx sein, wobei X ein kleiner Wert ist.
Wir landen bei etwas wie diesem
shape-outside: repeating-linear-gradient(#0000 0 calc(var(--f) - 3px),#000 0 var(--f));
Und dem folgenden Ergebnis

shape-outside wird auf das gefloate Element angewendet und erzeugt einen gefloaten Bereich mit einem vorgegebenen linearen Verlauf.Sehen Sie das? Die Form unseres wiederholten linearen Verlaufs drückt jede zweite Reihe um die halbe Breite eines Sechsecks nach rechts, um das Muster auszugleichen.
Fassen wir das alles zusammen
.main {
display:flex;
--s: 100px; /* size */
--m: 4px; /* margin */
--f: calc(var(--s) * 1.732 + 4 * var(--m) - 1px);
}
.container {
font-size: 0; /* disable white space between inline block element */
}
.container div {
width: var(--s);
margin: var(--m);
height: calc(var(--s) * 1.1547);
display: inline-block;
font-size:initial;
clip-path: polygon(0% 25%, 0% 75%, 50% 100%, 100% 75%, 100% 25%, 50% 0%);
margin-bottom: calc(var(--m) - var(--s) * 0.2885);
}
.container::before {
content: "";
width: calc(var(--s) / 2 + var(--m));
float: left;
height: 120%;
shape-outside: repeating-linear-gradient(#0000 0 calc(var(--f) - 3px), #000 0 var(--f));
}
Das war's! Mit nicht mehr als 15 CSS-Deklarationen haben wir ein responsives Raster, das sich gut in alle Bildschirmgrößen einfügt und das wir einfach anpassen können, indem wir zwei Variablen steuern.
Sie werden vielleicht bemerkt haben, dass ich der Variablen F -1px hinzufüge. Da wir mit Berechnungen zu tun haben, die Dezimalzahlen beinhalten, kann das Runden zu schlechten Ergebnissen führen. Um dies zu vermeiden, fügen wir ein paar Pixel hinzu oder ziehen sie ab. Ich verwende auch 120% anstelle von 100% für die Höhe des gefloaten Elements aus ähnlichen Gründen. Es gibt keine besondere Logik mit diesen Werten; wir passen sie einfach an, um sicherzustellen, dass die meisten Fälle abgedeckt werden, ohne unsere Formen zu verzerren.
Mehr Formen gewünscht?
Mit diesem Ansatz können wir mehr als nur Sechsecke erstellen! Erstellen wir stattdessen ein „Rauten“-Gitter. Auch hier beginnen wir mit unserem clip-path, um die Form zu erstellen

Der Code ist im Grunde derselbe. Was sich ändert, sind die Berechnungen und Werte. Unten finden Sie eine Tabelle, die die Änderungen veranschaulicht.
| Sechseckraster | Rautenraster | |
|---|---|---|
height | calc(var(--s)*1.1547) | var(--s) |
clip-path | polygon(0% 25%, 0% 75%, 50% 100%, 100% 75%, 100% 25%, 50% 0%) | polygon(50% 0, 100% 50%, 50% 100%, 0 50%) |
margin-bottom | calc(var(--m) - var(--s)*0.2885) | calc(var(--m) - var(--s)*0.5) |
--f | calc(var(--s)*1.7324 + 4*var(--m)) | calc(var(--s) + 4*var(--m)) |
Und wir sind fertig! Nur vier Änderungen an unserem Code ergeben ein komplett neues Raster, aber mit einer anderen Form.
Wie flexibel ist das?
Wir haben gesehen, wie wir das Sechseck- und Rautenraster mit genau derselben Code-Struktur, aber unterschiedlichen Variablen erstellen konnten. Lassen Sie mich Ihren Verstand mit einer weiteren Idee sprengen: Was wäre, wenn wir diese Berechnung zu einer Variablen machen, damit wir einfach zwischen verschiedenen Rastern wechseln können, ohne den Code zu ändern? Das können wir sicherlich tun!
Wir verwenden eine achteckige Form, da dies eine allgemeinere Form ist, mit der wir andere Formen (ein Sechseck, eine Raute, ein Rechteck usw.) erstellen können, indem wir einfach ein paar Werte ändern.

clip-path-Eigenschaft definiert.Unser Achteck wird mit vier Variablen definiert
S: die Breite.R: das Verhältnis, das uns hilft, die Höhe basierend auf der Breite zu definieren.hcundvc: beide steuern unsereclip-path-Werte und die gewünschte Form.hcbasiert auf der Breite, währendvcauf der Höhe basiert
Ich weiß, es sieht umfangreich aus, aber der clip-path ist mit acht Punkten definiert (wie in der Abbildung gezeigt). Mit einigen CSS-Variablen erhalten wir Folgendes:
clip-path: polygon(
var(--hc) 0, calc(100% - var(--hc)) 0, /* 2 points at the top */
100% var(--vc),100% calc(100% - var(--vc)), /* 2 points at the right */
calc(100% - var(--hc)) 100%, var(--hc) 100%, /* 2 points at the bottom */
0 calc(100% - var(--vc)),0 var(--vc) /* 2 points at the left */
);
Darauf arbeiten wir hin

Zoomen wir hinein, um die verschiedenen Werte zu identifizieren

Die Überlappung zwischen jeder Reihe (illustriert durch den roten Pfeil) kann mit der Variable vc ausgedrückt werden, was uns einen margin-bottom von M - vc ergibt (wobei M unser Rand ist).
Zusätzlich zum Rand, den wir zwischen unseren Elementen angewendet haben, benötigen wir auch einen zusätzlichen horizontalen Rand (illustriert durch den gelben Pfeil), der gleich S - 2*hc ist. Definieren wir eine weitere Variable für den horizontalen Rand (MH), die gleich M + (S - 2*hc)/2 ist.
Die Höhe von zwei Reihen ist gleich dem Doppelten der Größe einer Form (plus des Randes), abzüglich zweimal der Überlappung, oder 2*(S + 2*M) - 2*vc.
Aktualisieren wir unsere Wertetabelle, um zu sehen, wie wir die Berechnungen zwischen den verschiedenen Rastern durchführen
| Sechseckraster | Rautenraster | Achteckraster | |
|---|---|---|---|
height | calc(var(--s)*1.1547) | var(--s) | calc(var(--s)*var(--r))) |
clip-path | polygon(0% 25%, 0% 75%, 50% 100%, 100% 75%, 100% 25%, 50% 0%) | polygon(50% 0, 100% 50%, 50% 100%, 0 50%) | polygon(var(--hc) 0, calc(100% - var(--hc)) 0,100% var(--vc),100% calc(100% - var(--vc)), calc(100% - var(--hc)) 100%,var(--hc) 100%,0 calc(100% - var(--vc)),0 var(--vc)) |
--mh | – | – | calc(var(--m) + (var(--s) - 2*var(--hc))/2) |
margin | var(--m) | var(--m) | var(--m) var(--mh) |
margin-bottom | calc(var(--m) - var(--s)*0.2885) | calc(var(--m) - var(--s)*0.5) | calc(var(--m) - var(--vc)) |
--f | calc(var(--s)*1.7324 + 4*var(--m)) | calc(var(--s) + 4*var(--m)) | calc(2*var(--s) + 4*var(--m) - 2*var(--vc)) |
Okay, aktualisieren wir unser CSS mit diesen Anpassungen
.main {
display: flex;
--s: 100px; /* size */
--r: 1; /* ratio */
/* clip-path parameter */
--hc: 20px;
--vc: 30px;
--m: 4px; /* vertical margin */
--mh: calc(var(--m) + (var(--s) - 2*var(--hc))/2); /* horizontal margin */
--f: calc(2*var(--s) + 4*var(--m) - 2*var(--vc) - 2px);
}
.container {
font-size: 0; /* disable white space between inline block element */
}
.container div {
width: var(--s);
margin: var(--m) var(--mh);
height: calc(var(--s)*var(--r));
display: inline-block;
font-size: initial;
clip-path: polygon( ... );
margin-bottom: calc(var(--m) - var(--vc));
}
.container::before {
content: "";
width: calc(var(--s)/2 + var(--mh));
float: left;
height: 120%;
shape-outside: repeating-linear-gradient(#0000 0 calc(var(--f) - 3px),#000 0 var(--f));
}
Wie wir sehen, ist die Code-Struktur dieselbe. Wir haben lediglich mehr Variablen hinzugefügt, um die Form zu steuern und die margin-Eigenschaft zu erweitern.
Und hier ein funktionierendes Beispiel. Passen Sie die verschiedenen Variablen an, um die Form zu steuern, während Sie ein vollständig responsives Raster haben
Eine interaktive Demo, sagen Sie? Na klar!
Um die Dinge zu vereinfachen, drücke ich vc und hc als Prozentsatz von Breite und Höhe aus, damit wir unsere Elemente leicht skalieren können, ohne den clip-path zu beschädigen
Aus dem Obigen können wir leicht das anfängliche sechseckige Gitter erhalten

Das Rautenraster

Und noch ein Sechseckgitter

Ein Mauermörtel-ähnliches Gitter

Und ein Schachbrettmuster, während wir schon dabei sind

Viele Möglichkeiten, ein responsives Raster mit jeder Art von Form zu erstellen! Alles, was wir tun müssen, ist, ein paar Variablen anzupassen.
Die Ausrichtung korrigieren
Versuchen wir, die Ausrichtung unserer Formen zu steuern. Da wir mit inline-block-Elementen arbeiten, haben wir es mit der standardmäßigen Linksausrichtung und etwas leerem Platz am Ende zu tun, abhängig von der Ansichtsfensterbreite.
Beachten Sie, dass wir je nach Bildschirmbreite zwischen zwei Arten von Gittern wechseln

N, N-1,N, N-1, usw.)Raster Nr. 2: Die gleiche Anzahl von Elementen pro Zeile (
N, N, N, N, usw.)Es wäre gut, immer eines der beiden Raster zu haben (entweder Nr. 1 oder Nr. 2) und alles zu zentrieren, so dass der freie Platz gleichmäßig auf beide Seiten aufgeteilt ist.
Um das erste Raster in der obigen Abbildung zu erhalten, muss die Containerbreite ein Vielfaches der Größe einer Form plus ihres Rands sein, also N*(S + 2*MH), wobei N ein ganzzahliger Wert ist.
Das mag mit CSS unmöglich erscheinen, ist aber tatsächlich möglich. Ich habe es mit CSS-Grid gemacht
.main {
display: grid;
grid-template-columns: repeat(auto-fit, calc(var(--s) + 2*var(--mh)));
justify-content: center;
}
.container {
grid-column: 1/-1;
}
.main ist jetzt ein Grid-Container. Mit grid-template-columns definiere ich die Spaltenbreite (wie zuvor erklärt) und verwende den Wert auto-fit, um so viele Spalten wie möglich in den verfügbaren Platz zu bekommen. Dann überspannt der .container alle Grid-Spalten mit 1/-1 – was bedeutet, dass die Breite unseres Containers ein Vielfaches der Größe einer Spalte ist.
Alles, was benötigt wird, um die Dinge zu zentrieren, ist justify-content: center.
Ja, CSS ist Magie!
Vergrößern Sie die Demo und beachten Sie, dass wir nicht nur das erste Raster aus der Abbildung haben, sondern alles perfekt zentriert ist.
Aber warten Sie, wir haben display: flex entfernt und durch display: grid ersetzt… wie funktioniert die prozentuale Höhe des Floats immer noch? Ich sagte doch, dass die Verwendung eines Flex-Containers der Schlüssel dafür sei, oder?
Nun, es stellt sich heraus, dass CSS Grid diese Funktion auch bietet. Aus der Spezifikation
Sobald die Größe jedes Grid-Bereichs somit festgelegt ist, werden die Grid-Elemente in ihre jeweiligen Containerblöcke gelegt. Die Breite und Höhe des Grid-Bereichs gelten zu diesem Zweck als definiert.
Hinweis: Da Formeln, die nur mit definierten Größen berechnet werden, wie die Stretch-Fit-Formel, ebenfalls definiert sind, gilt die Größe eines Grid-Elements, das gestreckt wird, ebenfalls als definiert.
Ein Grid-Element hat standardmäßig eine stretch-Ausrichtung, sodass seine Höhe definiert ist, was bedeutet, dass die Verwendung eines Prozentsatzes als Höhe darin perfekt gültig ist.
Nehmen wir an, wir möchten stattdessen das zweite Raster in der Abbildung – wir fügen eine zusätzliche Spalte mit einer Breite hinzu, die der halben Breite der anderen Spalten entspricht
.main {
display: grid;
grid-template-columns: repeat(auto-fit,calc(var(--s) + 2*var(--mh))) calc(var(--s)/2 + var(--mh));
justify-content :center;
}
Nun haben wir nicht nur ein vollkommen responsives Raster, das flexibel genug ist, um benutzerdefinierte Formen anzunehmen, sondern alles ist auch perfekt zentriert!
Überlauf bekämpfen
Die Verwendung von negativem margin-bottom bei den letzten Elementen und das Element, das unsere Elemente verschiebt, erzeugen einen unerwünschten Überlauf, der den Inhalt nach unserem Raster beeinträchtigen kann.
Wenn Sie die Demo vergrößern und verkleinern, werden Sie einen Überlauf bemerken, der dem negativen Versatz entspricht, und manchmal ist er größer. Die Lösung ist, unserem Container etwas padding-bottom hinzuzufügen. Ich werde das Padding gleich der Höhe einer Form machen
Ich muss zugeben, dass es keine perfekte Lösung gibt, um diesen Überlauf zu bekämpfen und den Platz unter unserem Raster zu kontrollieren. Dieser Platz hängt von vielen Faktoren ab und wir müssen möglicherweise für jeden Fall einen anderen Padding-Wert verwenden. Die sicherste Lösung ist, einen großen Wert anzunehmen, der die meisten Fälle abdeckt.
Warten Sie, noch eins: ein Pyramidenraster
Nehmen wir alles, was wir gelernt haben, und bauen wir ein weiteres erstaunliches Raster. Diesmal verwandeln wir das gerade erstellte Raster in ein pyramidenförmiges.
Beachten Sie, dass im Gegensatz zu den bisherigen Rastern die Anzahl der Elemente wichtig ist, insbesondere für den responsiven Teil. Es ist erforderlich, die Anzahl der Elemente und genauer gesagt die Anzahl der Reihen zu kennen.

Das bedeutet nicht, dass wir eine Menge hartkodierter Werte benötigen. Stattdessen verwenden wir eine zusätzliche Variable, um die Dinge basierend auf der Anzahl der Reihen anzupassen.
Die Logik basiert auf der Anzahl der Reihen, da unterschiedliche Anzahlen von Elementen uns die gleiche Anzahl von Reihen ergeben können. Zum Beispiel gibt es fünf Reihen, wenn wir zwischen 11 und 15 Elemente haben, auch wenn die letzte Reihe nicht vollständig belegt ist. Zwischen 16 und 21 Elementen ergeben sich sechs Reihen und so weiter. Die Anzahl der Reihen ist unsere neue Variable.
Bevor wir uns mit der Geometrie und der Mathematik beschäftigen, hier ist eine funktionierende Demo
Beachten Sie, dass der Großteil des Codes derselbe ist wie in den vorherigen Beispielen. Konzentrieren wir uns also auf die neuen Eigenschaften, die wir hinzugefügt haben
.main {
--nr: 5; /* number of rows */
}
.container {
max-width: calc(var(--nr)*(var(--s) + 2*var(--mh)));
margin: 0 auto;
}
.container::before ,
.container i {
content: "";
width: calc(50% - var(--mh) - var(--s)/2);
float: left;
height: calc(var(--f)*(var(--nr) - 1)/2);
shape-outside: linear-gradient(to bottom right, #000 50%, #0000 0);
}
.container i {
float:right;
shape-outside: linear-gradient(to bottom left, #000 50%, #0000 0);
}
NR ist unsere Variable für die Anzahl der Reihen. Die Breite des Containers muss gleich der letzten Reihe der Pyramide sein, um sicherzustellen, dass sie alle Elemente aufnimmt. Wenn Sie sich die vorherige Abbildung ansehen, werden Sie feststellen, dass die Anzahl der Elemente in der letzten Reihe einfach gleich der Anzahl der Reihen ist, was bedeutet, dass die Formel lautet: NR* (S + 2*MH).
Sie werden vielleicht auch bemerkt haben, dass wir dort auch ein <i>-Element hinzugefügt haben. Das haben wir getan, weil wir zwei schwebende Elemente benötigen, auf die wir shape-outside anwenden werden.
Um zu verstehen, warum wir zwei schwebende Elemente benötigen, sehen wir uns an, was im Hintergrund passiert

Die blauen Elemente sind unsere schwebenden Elemente. Jedes hat eine Breite, die der Hälfte der Containergröße entspricht, abzüglich der halben Formgröße, plus Rand. Die Höhe entspricht in unserem Fall vier Reihen und in einem allgemeineren Fall NR - 1. Zuvor haben wir die Höhe von zwei Reihen, F, definiert, also ist die Höhe einer Reihe F/2. So sind wir auf height: calc(var(--f)*(var(--nr) - 1)/2 gekommen.
Nachdem wir nun die Größe unserer Elemente haben, müssen wir unserem shape-outside einen Verlauf zuweisen.
Die lila Färbung in der obigen Abbildung ist der eingeschränkte Bereich für unsere Elemente (er muss eine opake Farbe haben). Der verbleibende Bereich ist der freie Raum, in dem die Elemente fließen können (er muss eine transparente Farbe haben). Dies kann mit einem diagonalen Verlauf erreicht werden
shape-outside: linear-gradient(to bottom right, #000 50%, #0000 0);
Wir ändern einfach right in left für das andere schwebende Element. Sie haben wahrscheinlich bemerkt, dass dies nicht responsiv ist. Tatsächlich vergrößern und verkleinern Sie die Ansichtsfensterbreite der Demo und sehen Sie, wie unresponsive das ist.
Wir haben ein paar Optionen, um es responsiv zu machen
- Wir können auf das erste Raster zurückgreifen, wenn die Containerbreite kleiner als die Ansichtsfensterbreite ist. Es ist etwas knifflig zu codieren, aber es erlaubt uns, die gleiche Größe für unsere Elemente beizubehalten.
- Wir können die Größe unserer Elemente reduzieren, um das Pyramidenraster beizubehalten. Das ist einfacher zu codieren mit dem prozentbasierten Trick, aber das könnte auf kleineren Bildschirmen zu winzigen Elementen führen.
Nehmen wir die erste Lösung. Wir mögen eine gute Herausforderung, oder?
Um das Pyramidenraster zu erhalten, benötigten wir zwei schwebende Elemente. Das ursprüngliche Raster benötigte nur ein schwebendes Element. Glücklicherweise erlaubt uns unsere Struktur, **drei** schwebende Elemente zu haben, ohne weitere Elemente zum Markup hinzufügen zu müssen, dank Pseudo-Elementen. Wir werden container::before, i::before, i::after verwenden
/* Same as before... */
/* The initial grid */
.container::before {
content: "";
width: calc(var(--s)/2 + var(--mh));
float: left;
height: 120%;
shape-outside: repeating-linear-gradient(#0000 0 calc(var(--f) - 3px),#000 0 var(--f));
}
/* The pyramidal grid */
.container i::before ,
.container i::after {
content: "";
width: calc(50% - var(--mh) - var(--s)/2);
float: left;
height: calc(var(--f)*(var(--nr) - 1)/2);
shape-outside: linear-gradient(to bottom right,#000 50%,#0000 0);
}
.container i::after {
float:right;
shape-outside: linear-gradient(to bottom left,#000 50%,#0000 0);
}
Jetzt brauchen wir einen Trick, der es uns erlaubt, entweder das erste schwebende Element oder die anderen beiden zu verwenden, aber nicht alle gleichzeitig. Diese Bedingung sollte auf der Breite unseres Containers basieren
- Wenn die Containerbreite größer ist als die Breite der letzten Reihe, können wir unsere Pyramide haben und die schwebenden Elemente innerhalb von
<i>verwenden. - Wenn die Containerbreite kleiner ist als die Breite der letzten Reihe, wechseln wir zum anderen Raster und verwenden das erste schwebende Element.
Dafür können wir clamp() verwenden! Es ist eine Art bedingte Funktion, die einen minimalen und maximalen Bereich festlegt und innerhalb dieses Bereichs einen „idealen“ Wert angibt. Auf diese Weise können wir zwischen Rastern „wechseln“, indem wir unsere Formeln als geklemmte Werte verwenden und dennoch Media Queries vermeiden.
Unser Code wird so aussehen
.main {
/* the other variables won't change*/
--lw: calc(var(--nr)*(var(--s) + 2*var(--mh))); /* width of last row */
}
.container {
max-width: var(--lw);
}
/* The initial grid */
.container::before {
width: clamp(0px, (var(--lw) - 100%)*1000, calc(var(--s)/2 + var(--mh)));
}
/* The pyramidal grid */
.container i::before,
.container i::after {
width: clamp(0px, (100% - var(--lw) + 1px)*1000, calc(50% - var(--mh) - var(--s)/2));
}
Auf größeren Bildschirmen entspricht die Breite des Containers (LW) nun seinem max-width, also 100% == LW. Das bedeutet, dass die Breite von .container::before gleich 0px ist (und dieses schwebende Element deaktiviert wird).
Für die anderen schwebenden Elemente klemmen wir die Breite
width: clamp(0px, (100% - var(--lw) + 1px)*1000, calc(50% - var(--mh) - var(--s)/2));
…wobei der mittlere Wert ((100% - LW + 1px)*1000) gleich (0 + 1px)*1000 = 1000px ist (ein absichtlich großer, aber willkürlicher Wert). Er wird auf calc(50% - var(--mh) - var(--s)/2) geklemmt. Mit anderen Worten, diese schwebenden Elemente werden mit der richtigen Breite aktiviert (die wir zuvor definiert haben)
Voilà! Wir haben eine pyramidenförmige Form auf großen Bildschirmen.
Wenn nun die Containerbreite kleiner wird, ist LW größer als 100%. Also wird (LW - 100%) positiv sein. Multipliziert mit einem großen Wert, wird es auf calc(var(--s)/2 + var(--mh)) geklemmt, was das erste schwebende Element aktiviert. Für die anderen schwebenden Elemente ergibt (100% - LW + 1px) einen negativen Wert und wird auf 0px geklemmt, was die schwebenden Elemente deaktiviert.
Vergrößern und verkleinern Sie die untenstehende Demo und sehen Sie, wie wir zwischen beiden Rastern wechseln
Versuchen wir, mehr Elemente hinzuzufügen
Sehen Sie das? Die Dinge skalieren perfekt. Werfen wir ihm noch mehr Elemente zum Spaß zu
Immer noch großartig. Beachten Sie, dass die letzte Reihe nicht einmal voll ist. Das zeigt nur, dass dieser Ansatz eine Menge Fälle abdeckt. Wir können dies auch mit dem CSS-Grid-Ausrichtungstrick kombinieren, den wir zuvor verwendet haben
Denken Sie, dass „float“ jetzt so schlimm ist?
Möchten Sie die Pyramide umkehren?

Wie in der obigen Abbildung gezeigt, können zwei Änderungen am vorherigen Code unsere Pyramide umkehren
- Ich ändere die Richtung des Verlaufs von
to bottom left|rightaufto top left|right, - Ich füge einen
margin-tophinzu, der der Höhe einer Reihe entspricht.
Und, hey, wir können einfach zwischen beiden Pyramiden wechseln
Ist das nicht schön? Wir haben ein responsives Pyramidenraster mit benutzerdefinierten Formen, das wir leicht umkehren können und das auf kleinen Bildschirmen auf ein anderes responsives Raster zurückfällt, während alles perfekt zentriert ist. Das alles ohne eine einzige Media Query oder JavaScript, sondern stattdessen mit der oft übersehenen float-Eigenschaft.
Sie werden wahrscheinlich in einigen Fällen eine gewisse Fehlausrichtung bemerken. Ja, das sind wieder Rundungsprobleme, die mit den von uns durchgeführten Berechnungen zusammenhängen und der Tatsache, dass wir versuchen, dies mit den interaktiven Demos generisch zu gestalten. Um dies zu beheben, passen wir einfach einige Werte manuell an (insbesondere den Prozentsatz des Verlaufs), bis wir wieder eine perfekte Ausrichtung erhalten.
Das ist ein Float Wrap!
Da haben wir es: Die Kombination von float mit shape-outside kann uns helfen, komplexe, flexible und responsive Layouts zu erstellen – lang lebe float!
Der Artikel endet hier, aber das ist erst der Anfang. Ich habe Ihnen das Layout bereitgestellt und Sie können jetzt problemlos beliebige Inhalte in die Divs einfügen, Hintergründe, Schatten, Animationen usw. anwenden.
Einfach nur wow!
Fantastisch! Vielen Dank für diesen Artikel, Temani.
Lange nicht mehr etwas von dieser Qualität und Authentizität gelesen.
Glückwunsch zu all der Arbeit und dem Verstand dahinter.
Chapeau!
Danke, ich schätze den Kommentar :)
CGP Grey wäre stolz.
Okay, dieser Artikel hat das Niveau an Einblick und Vollständigkeit von Ana Tudor… Danke, Temani!
Oh, ich werde mit Ana Tudor verglichen! Das ist tatsächlich das beste Kompliment :)
Dieser Leitfaden ist vielleicht der beste, den ich bisher auf dieser Seite gelesen habe.
Gute Arbeit. Ich habe lange versucht, dieses Mosaik herauszufinden. Gibt es eine einfache Möglichkeit, es als ein Objekt von der äußersten linken Ecke ausgehen zu lassen und dann Formen um das Original herum hinzuzufügen, wenn mit dem Inhalt des Originals interagiert wird, indem man darauf klickt oder Text eingibt? Ich stelle mir vor, dass dies mehr als nur CSS und HTML erfordern könnte.
Können Sie mir ein Mockup dessen zeigen, was Sie beschreiben? Ich kann mir nicht vorstellen, was Sie wollen
Tolle Arbeit, Temani!
Großartig, aber es gibt ein kleines Problem, wenn Informationen in die Divs passen müssen.
Fügen Sie overflow:hidden; im CSS hinzu
Es ist kein wirkliches Problem. Alles hängt von der Größe der Elemente und des Inhalts ab. Sie werden logischerweise einen Überlauf haben, wenn Sie viel Inhalt in ein kleines Element packen. Das ist etwas, dem Sie bei jeder Art von Layout begegnen werden, nicht nur bei dem, das ich beschreibe.
Ich stimme zu :)
Aber ich habe noch 2 andere seltsame Verhaltensweisen.
Auf meiner Testseite. Stellen Sie die Breite des Browsers auf 4 Elemente ein.
1. Bij board sehen Sie, dass die Elemente 31 bis 34 nicht korrekt sind. Gleiches gilt nach jeweils 8 Zeilen und Gleiches mit Octagon (Element 14-17) alle 7 Zeilen.
2. Der Anfang von Rhombus überragt das Ende von Oktagonen
Wo habe ich mich geirrt?
Danke Jan
Wie ich im Artikel beschrieben habe, können Sie aufgrund von Rundungsfehlern in einigen besonderen Fällen auf Ausrichtungsfehler stoßen und wir müssen einige Werte manuell korrigieren. Es kann auch etwas anderes in Ihrem Code sein.
Wenn Sie mir den Code zeigen können, kann ich wahrscheinlich herausfinden, was vor sich geht.
Ich habe die Website ausgefüllt. Aber sie wird in den Nachrichten nicht angezeigt :-(
Der gesamte Test ist auf dieser Webseite https://www.janr.be/grids/
Bitte überprüfen Sie die von Ihnen verwendeten Berechnungen. Sie sind falsch, daher liegt das Problem nicht an meinem Ansatz, sondern Sie haben die falschen Werte gewählt. Das F kann nicht dasselbe sein für Schachbrett, Sechseck und Achteck.
Nur die Raute und das Sechseck verwenden die korrekten Werte in Ihrem Code und wie Sie sehen können, gibt es keine Probleme damit.
Beachten Sie auch den Abschnitt „Den Überlauf bekämpfen“, in dem ich den von Ihnen auftretenden Überlauf erkläre und wie Sie ihn beheben können.
Das ist erstaunlich! Vielen Dank für die detaillierte Erklärung.
Ich entdecke ein Problem, wenn die Bildschirmgröße bei kleineren Sechsecken reduziert wird. Dies könnte mit den Rundungsfehlern zusammenhängen, die Sie beim Berechnen des –f-Werts für „repeating-linear-gradient“ erwähnt haben. Hier ist ein Beispiel für das, was ich sehe. Ich habe Ihr Beispiel kopiert, die –s- und –m-Werte reduziert und einen Wrap-Div mit einer Breite von 10 % hinzugefügt. Haben Sie eine Idee, was vor sich geht oder wie man es beheben kann? https://codepen.io/micahalgard/pen/BaRpzrq
Ja, tatsächlich ist es ein Rundungsfehler. In Ihrem Fall ist das von mir hinzugefügte -1px zu groß. Reduzieren Sie es auf -.3px, und es sollte in Ordnung sein. Versuchen Sie immer, mit diesem zusätzlichen Wert zu spielen, bis Sie eine perfekte Ausrichtung erzielen.
Toller Artikel, ABER was ist mit einem Sechseck ohne Farbe, transparentem Hintergrund, aber mit einem Rahmen von sagen wir 5px?
Das scheint ziemlich schwierig zu erreichen zu sein. Haben Sie Ideen? Bitte posten Sie Ihren Code dafür, denn das scheint mit diesem Code nicht möglich zu sein
Ich habe einen Artikel darüber geschrieben, wie man Rahmen zu komplexen Formen hinzufügt: https://css-tricks.de/exploring-the-css-paint-api-polygon-border/ aber die Browserunterstützung ist immer noch nicht gut
Kann ich die erste, dritte, fünfte usw. Zeile auch mit dem repeating-linear-gradient CSS nach rechts verschieben?
Aber wirklich toller Artikel :)
Hilft sehr
Ja, das können Sie. Sie müssen den Verlauf so aktualisieren, dass er mit der soliden Farbgebung beginnt.
Hier ist ein Beispiel aus dem Artikel, bei dem ich den Verlauf aktualisiert habe: https://codepen.io/t_afif/pen/LYzLVra
Können Sie den Code auch für die anderen Beispiele verfügbar machen? Ich brauche die Sechseckkarte mit flacher Oberseite und nicht mit spitzer Oberseite, und ich bekomme es nicht zum Laufen.
Dieses Beispiel ist bereits im Artikel. Sie haben beide Sechseckformen.
Das ist unglaublich, danke!
Hallo Kumpel, danke für das Teilen dieses tollen Beitrags!
Gibt es ein Beispiel für Kreise? Bei diesen Formeln sehe ich keine erwarteten Ränder/Werte für einen clip-path, der circle(50% at 50% 50%) entspricht.
Danke für deine Hilfe! <3
Hallo Mann, es gibt einige Beispiele, die in Safari nicht funktionieren, weißt du warum?
Vielen Dank im Voraus!
Großartig – ich versuche seit Tagen, Sechsecke auf eine Website zu setzen!
Ich habe jedoch ein Problem damit, dass das erste Sechseck auf meinem Handy überlappt wird. Kannst du helfen?
Danke
Es ist erstaunlich, wie flexibel und einfach es ist, es für das zu bekommen, was ich brauche.
Ich habe jedoch ein kleines Problem damit, einen Hintergrund für die Sechsecke zu haben, da sie ihn überlaufen. Gibt es eine Lösung dafür?
Danke.
Vielen Dank für all diese Arbeit! Das obige Beispiel ist das, was ich anstrebe, aber ich möchte angrenzende weiße Hexes mit einem schwarzen Rand erstellen. Ein Wabenmuster für ein Hex-Raster.
Ich habe versucht, diesen Stil in .container div hinzuzufügen
border: 2px solid black;Aber das wendet keinen Rand auf die diagonalen Linien jedes Sechsecks an. Ich ziele auf etwas ab, das in einem Browser so aussieht.
https://www.istockphoto.com/vector/seamless-contour-hexagon-background-gm673364210-123369199