Bilder in einem Rasterlayout vergrößern

Avatar of Temani Afif
Temani Afif am

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

Das Erstellen eines Bilderraster ist dank CSS Grid einfach. Aber das Gitter dazu zu bringen, schicke Dinge zu tun, *nachdem* die Bilder platziert wurden, kann schwierig sein.

Stellen Sie sich vor, Sie möchten den Bildern einen schicken Hover-Effekt hinzufügen, bei dem sie wachsen und über die Zeilen und Spalten hinauszoomen, in denen sie sich befinden? Das können wir machen!

Cool, oder? Wenn Sie sich den Code ansehen, werden Sie kein JavaScript, keine komplexen Selektoren oder gar magische Zahlen finden. Und das ist nur ein Beispiel von vielen, die wir untersuchen werden!

Das Raster erstellen

Der HTML-Code zur Erstellung des Rasters ist so einfach wie eine Liste von Bildern innerhalb eines Containers. Mehr brauchen wir nicht.

<div class="gallery">
  <img>
  <img>
  <img>
  <!-- etc. -->
</div>

Für das CSS beginnen wir zunächst mit der Einrichtung des Rasters mit folgendem:

.gallery {
  --s: 150px; /* controls the size */
  --g: 10px;  /* controls the gap */

  display: grid;
  gap: var(--g);
  width: calc(3*var(--s) + 2*var(--g)); /* 3 times the size plus 2 times the gap */
  aspect-ratio: 1;
  grid-template-columns: repeat(3, auto);
}

Kurz gesagt, wir haben zwei Variablen: eine, die die Größe der Bilder steuert, und eine, die die Größe des Abstands zwischen den Bildern festlegt. aspect-ratio hilft, die Proportionen beizubehalten.

Sie fragen sich vielleicht, warum wir nur drei Spalten, aber keine Zeilen definieren. Nein, ich habe die Zeilen nicht vergessen – wir müssen sie nicht explizit festlegen. CSS Grid kann Elemente automatisch auf impliziten Zeilen und Spalten platzieren, was bedeutet, dass wir so viele Zeilen erhalten, wie für eine beliebige Anzahl von Bildern benötigt werden. Wir können die Zeilen stattdessen explizit definieren, aber wir müssen grid-auto-flow: column hinzufügen, um sicherzustellen, dass der Browser die benötigten Spalten erstellt.

Hier ist ein Beispiel, das beide Fälle veranschaulicht. Der Unterschied besteht darin, dass die eine in row-Richtung fließt und die andere in column-Richtung.

Schauen Sie sich diesen anderen Artikel an, den ich geschrieben habe, um mehr über implizite RASTER und den automatischen Platzierungsalgorithmus zu erfahren.

Nachdem wir nun unser Raster haben, ist es an der Zeit, die Bilder zu gestalten

.gallery > img {
  width: 0;
  height: 0;
  min-height: 100%;
  min-width: 100%;
  object-fit: cover;
}

Der Hover-Effekt, den wir erstellen, basiert auf diesem CSS. Es sieht für Sie wahrscheinlich seltsam aus, dass wir Bildern sowohl keine Breite als auch keine Höhe geben, aber eine minimale Breite und Höhe von 100 % haben. Aber Sie werden sehen, dass es ein ziemlich cleverer Trick für das ist, was wir erreichen wollen.

Was ich hier tue, ist, dem Browser mitzuteilen, dass die Bilder eine Breite und Höhe von 0 haben müssen, aber auch eine Mindesthöhe gleich 100 % haben müssen ... aber 100 % wovon? Bei der Verwendung von Prozentwerten bezieht sich der Wert auf etwas anderes. In diesem Fall befindet sich unser Bild in einer Rasterzelle und wir müssen wissen, welche Größe 100 % entspricht.

Der Browser ignoriert zunächst min-height: 100 %, um die Größe der Rasterzellen zu berechnen, verwendet aber height: 0 in seiner Berechnung. Das bedeutet, dass unsere Bilder nicht zur Größe der Rasterzellen beitragen... da sie technisch gesehen keine physische Größe haben. Dies führt zu drei gleich großen Spalten und Zeilen, die auf der Größe des Rasters basieren (die wir auf der Breite von .gallery und aspect-ratio definiert haben). Die Höhe jeder Rasterzelle ist nichts anderes als die von uns definierte Variable --s (dasselbe für die Breite).

Nachdem wir nun die Abmessungen unserer Rasterzellen haben, verwendet der Browser diese mit min-height: 100 % (und min-width: 100 %), was die Bilder zwingt, den Platz jeder Rasterzelle vollständig auszufüllen. Das Ganze mag etwas verwirrend aussehen, aber die Hauptidee ist sicherzustellen, dass das Raster die Größe der Bilder bestimmt und nicht umgekehrt. Ich möchte nicht, dass das Bild die Größe des Rasters bestimmt, und das werden Sie verstehen, nachdem Sie den Hover-Effekt hinzugefügt haben.

Den Hover-Effekt erstellen

Was wir tun müssen, ist, die Skalierung der Bilder zu erhöhen, wenn sie gehovert werden. Das können wir tun, indem wir die width und height eines Bildes bei :hover anpassen.

.gallery {
  --f: 1.5; /* controls the scale factor */
}

.gallery img:hover{
  width:  calc(var(--s) * var(--f));
  height: calc(var(--s) * var(--f));
}

Ich habe eine neue benutzerdefinierte Variable, --f, hinzugefügt, um die Größe bei Hover zu steuern. Beachten Sie, wie ich die Größenvariable, --s, damit multipliziere, um die neue Bildgröße zu berechnen.

Aber Sie sagten, dass die Bildgröße 0 sein muss. Was ist los? Ich bin verloren...

Was ich gesagt habe, stimmt immer noch, aber ich mache eine Ausnahme für das gehoverte Bild. Ich sage dem Browser, dass nur ein Bild eine Größe hat, die nicht Null ist – sodass es zur Dimension des Rasters beiträgt –, während alle anderen gleich 0 bleiben.

Die linke Seite zeigt das Raster in seinem natürlichen Zustand ohne gehoverte Bilder, was die rechte Seite zeigt. Alle Rasterzellen auf der linken Seite sind gleich groß, da alle Bilder keine physischen Abmessungen haben.

Auf der rechten Seite ist das zweite Bild in der ersten Zeile gehovert, was ihm Abmessungen verleiht, die die Größe der Rasterzelle beeinflussen. Der Browser macht diese spezielle Rasterzelle beim Hovern größer, was zur Gesamtgröße beiträgt. Und da die Größe des gesamten Rasters festgelegt ist (da wir eine feste width für .gallery festgelegt haben), werden die anderen Rasterzellen logischerweise kleiner, um die Gesamtgröße von .gallery beizubehalten.

Das ist unser Zoom-Effekt in Aktion! Indem wir die Größe nur eines Bildes erhöhen, beeinflussen wir die gesamte Rasterkonfiguration, und wir haben zuvor gesagt, dass das Raster die Größe der Bilder bestimmt, sodass jedes Bild innerhalb seiner Rasterzelle gestreckt wird, um den gesamten Platz auszufüllen.

Dazu fügen wir einen Hauch von transition hinzu und verwenden object-fit, um Bildverzerrungen zu vermeiden, und die Illusion ist perfekt!

Ich weiß, dass die Logik hinter dem Trick nicht leicht zu verstehen ist. Machen Sie sich keine Sorgen, wenn Sie sie nicht vollständig verstehen. Am wichtigsten ist es, die Struktur des verwendeten Codes zu verstehen und wie man ihn modifiziert, um weitere Variationen zu erzielen. Das werden wir als Nächstes tun!

Weitere Bilder hinzufügen

Wir haben ein 3×3-Raster erstellt, um den Haupttrick zu erklären, aber Sie haben wahrscheinlich schon erraten, dass wir dort nicht aufhören müssen. Wir können die Anzahl der Spalten und Zeilen variabel gestalten und beliebig viele Bilder hinzufügen.

.gallery {
  --n: 3; /* number of rows*/
  --m: 4; /* number of columns */
  --s: 150px; /* control the size */
  --g: 10px;  /* control the gap */
  --f: 1.5;   /* control the scale factor */

  display: grid;
  gap: var(--g);
  width:  calc(var(--m)*var(--s) + (var(--m) - 1)*var(--g));
  height: calc(var(--n)*var(--s) + (var(--n) - 1)*var(--g));
  grid-template-columns: repeat(var(--m),auto);
}

Wir haben zwei neue Variablen für die Anzahl der Zeilen und Spalten. Dann definieren wir einfach die Breite und Höhe unseres Rasters damit. Dasselbe gilt für grid-template-columns, das die --m-Variable verwendet. Und genau wie zuvor müssen wir die Zeilen nicht explizit definieren, da die automatische Platzierungsfunktion von CSS Grid die Arbeit für uns erledigt, egal wie viele Bildelemente wir verwenden.

Warum nicht unterschiedliche Werte für Breite und Höhe? Das können wir machen

.gallery {
  --n: 3; /* number of rows*/
  --m: 4; /* number of columns */
  --h: 120px; /* control the height */
  --w: 150px; /* control the width */
  --g: 10px;  /* control the gap */
  --f: 1.5;   /* control the scale factor */

  display: grid;
  gap: var(--g);
  width:  calc(var(--m)*var(--w) + (var(--m) - 1)*var(--g));
  height: calc(var(--n)*var(--h) + (var(--n) - 1)*var(--g));
  grid-template-columns: repeat(var(--m),auto);
}

.gallery img:hover{
  width:  calc(var(--w)*var(--f));
  height: calc(var(--h)*var(--f));
}

Wir ersetzen --s durch zwei Variablen, eine für die Breite, --w, und eine für die Höhe, --h. Dann passen wir alles andere entsprechend an.

Wir haben also mit einem Raster mit fester Größe und fester Elementanzahl begonnen, dann aber ein neues Set von Variablen erstellt, um jede gewünschte Konfiguration zu erhalten. Alles, was wir tun müssen, ist, beliebig viele Bilder hinzuzufügen und die CSS-Variablen entsprechend anzupassen. Die Kombinationen sind grenzenlos!

Wie wäre es mit einer Vollbildversion? Ja, das ist auch möglich. Alles, was wir brauchen, ist zu wissen, welche Werte wir unseren Variablen zuweisen müssen. Wenn wir N Zeilen von Bildern wünschen und unser Raster im Vollbildmodus sein soll, müssen wir zuerst eine Höhe von 100vh berechnen.

var(--n) * var(--h) + (var(--n) - 1) * var(--g) = 100vh

Gleiche Logik für die Breite, aber mit vw statt vh.

var(--m) * var(--w) + (var(--m) - 1) * var(--g) = 100vw

Wir führen die Berechnung durch, um Folgendes zu erhalten:

--w: (100vw - (var(--m) - 1) * var(--g)) / var(--m)
--h: (100vh - (var(--n) - 1) * var(--g)) / var(--n)

Fertig!

Es ist exakt derselbe HTML-Code, aber mit einigen aktualisierten Variablen, die die Größenänderung und das Verhalten des Rasters verändern.

Beachten Sie, dass ich die Formel, die wir zuvor für die width und height von .gallery festgelegt hatten, weggelassen und sie durch 100vw bzw. 100vh ersetzt habe. Die Formel würde uns das gleiche Ergebnis liefern, aber da wir den gewünschten Wert kennen, können wir all diese zusätzliche Komplexität weglassen.

Wir können auch --h und --w vereinfachen, indem wir den Abstand aus der Gleichung entfernen und stattdessen Folgendes verwenden:

--h: calc(100vh / var(--n)); /* Viewport height divided by number of rows */
--w: calc(100vw / var(--m)); /* Viewport width divided by number of columns */

Dadurch wird das gehoverte Bild etwas größer als im vorherigen Beispiel, aber das ist keine große Sache, da wir die Skalierung mit der --f-Variable steuern können, die wir als Multiplikator verwenden.

Und da die Variablen an einer Stelle verwendet werden, können wir den Code weiter vereinfachen, indem wir sie ganz entfernen:

Es ist wichtig zu beachten, dass diese Optimierung nur für das Vollbildbeispiel und nicht für die zuvor behandelten Beispiele gilt. Dieses Beispiel ist ein Sonderfall, bei dem wir den Code durch Entfernen einiger komplexer Berechnungen, die wir in den anderen Beispielen benötigten, optimieren können.

Wir haben tatsächlich alles, was wir brauchen, um das beliebte Muster von sich erweiternden Panels zu erstellen

Tauchen wir noch tiefer ein

Haben Sie bemerkt, dass unser Skalierungsfaktor kleiner als 1 sein kann? Wir können die Größe des gehoverten Bildes kleiner als --h oder --w definieren, aber das Bild wird beim Hovern größer.

Die anfängliche Rasterzellengröße entspricht --w und --h, also warum machen kleinere Werte die Rasterzelle *größer*? Sollte die Zelle nicht *kleiner* werden oder zumindest ihre anfängliche Größe beibehalten? Und was ist die endgültige Größe der Rasterzelle?

Wir müssen tiefer in die Berechnung der Rasterzellengröße durch den CSS Grid-Algorithmus eintauchen. Und das beinhaltet das Verständnis der standardmäßigen **Stretch-Ausrichtung** von CSS Grid.

Hier ist ein Beispiel, um die Logik zu verstehen.

Auf der linken Seite des Demos habe ich eine Zweispalten mit auto-Breite definiert. Wir erhalten das intuitive Ergebnis: zwei gleich große Spalten (und zwei gleich große Rasterzellen). Aber das Raster, das ich auf der rechten Seite des Demos eingerichtet habe, wo ich die Ausrichtung mit place-content: start aktualisiere, scheint nichts zu haben.

DevTools hilft uns zu zeigen, was wirklich in beiden Fällen passiert.

Im zweiten Raster haben wir zwei Spalten, aber ihre Breiten sind Null, daher erhalten wir zwei Rasterzellen, die in der oberen linken Ecke des Rastercontainers zusammenfallen. Dies ist *kein* Fehler, sondern das logische Ergebnis der Rasterausrichtung. Wenn wir eine Spalte (oder Zeile) mit auto dimensionieren, bedeutet dies, dass ihr Inhalt ihre Größe bestimmt – aber wir haben eine leere div ohne Inhalt, der Platz schafft.

Da stretch jedoch die Standardausrichtung ist und wir genügend Platz in unserem Raster haben, dehnt der Browser beide Rasterzellen gleichmäßig aus, um diesen gesamten Bereich abzudecken. So erhält das Raster auf der linken Seite zwei gleich große Spalten.

Aus der Spezifikation

Beachten Sie, dass bestimmte Werte von justify-content und align-content dazu führen können, dass die Spuren auseinander platziert werden (space-around, space-between, space-evenly) oder umgrößert werden (stretch).

Beachten Sie "umgrößert werden", was hier der Schlüssel ist. Im letzten Beispiel habe ich place-content verwendet, was die Kurzschreibweise für justify-content und align-content ist.

Und das ist irgendwo in den Spezifikationen des Grid Sizing Algorithmus versteckt.

Dieser Schritt erweitert Tracks mit einer auto max track sizing function, indem jeglicher verbleibende positive, definitive freie Speicherplatz gleichmäßig auf sie verteilt wird. Wenn der freie Speicherplatz undefiniert ist, aber der Rastercontainer eine definierte min-Breite/Höhe hat, verwenden Sie diese Größe, um den freien Speicherplatz für diesen Schritt stattdessen zu berechnen.

„Gleichmäßig“ erklärt, warum wir gleich große Rasterzellen erhalten, aber es gilt für „den freien Speicherplatz“, was sehr wichtig ist.

Nehmen wir das vorherige Beispiel und fügen wir einer der divs Inhalt hinzu.

Wir haben ein quadratisches 50px-Bild hinzugefügt. Hier ist eine Illustration, wie jedes Raster in unserem Beispiel auf dieses Bild reagiert.

Im ersten Fall sehen wir, dass die erste Zelle (in Rot) größer ist als die zweite (in Blau). Im zweiten Fall ändert sich die Größe der ersten Zelle, um der physischen Größe des Bildes zu entsprechen, während die zweite Zelle dimensionslos bleibt. Der freie Speicherplatz wird gleichmäßig aufgeteilt, aber die erste Zelle hat mehr Inhalt, was sie größer macht.

Das ist die Mathematik, um unseren freien Speicherplatz zu ermitteln.

(grid width) - (gap) - (image width) = (free space)
200px - 5px - 50px = 145px 

Dividiert durch zwei – die Anzahl der Spalten – erhalten wir eine Breite von 72,5px für jede Spalte. Aber wir addieren die Größe des Bildes, 50px, zur ersten Spalte hinzu, was uns eine Spalte mit 122,5px und die zweite mit 72,5px übrig lässt.

Die gleiche Logik gilt für unser Bildraster. Alle Bilder haben eine Größe von 0 (kein Inhalt), während das gehoverte Bild zur Größe beiträgt – selbst wenn es nur 1px ist – was seine Rasterzelle größer macht als die anderen. Aus diesem Grund kann der Skalierungsfaktor jeder Wert größer als 0 sein, sogar Dezimalzahlen zwischen 0 und 1.

Um die endgültige Breite der Rasterzellen zu erhalten, führen wir die gleiche Berechnung durch, um Folgendes zu erhalten:

(container width) - (sum of all gaps) - (hovered image width) = (free space)

Die Breite des Containers wird definiert durch:

var(--m)*var(--w) + (var(--m) - 1)*var(--g)

...und alle Lücken sind gleich:

(var(--m) - 1)*var(--g)

...und für das gehoverte Bild haben wir:

var(--w)*var(--f)

Wir können all das mit unseren Variablen berechnen.

var(--m)*var(--w) - var(--w)*var(--f) = var(--w)*(var(--m) - var(--f))

Die Anzahl der Spalten wird durch --m definiert, also teilen wir diesen freien Speicherplatz gleichmäßig auf, um zu erhalten:

var(--w)*(var(--m) - var(--f))/var(--m)

...was uns die Größe der nicht gehoverten Bilder gibt. Für gehoverte Bilder haben wir dies:

var(--w)*(var(--m) - var(--f))/var(--m) + var(--w)*var(--f)
var(--w)*((var(--m) - var(--f))/var(--m) + var(--f))

Wenn wir die endgültige Größe des gehoverten Bildes steuern wollen, betrachten wir die obige Formel, um die exakte gewünschte Größe zu erhalten. Wenn wir zum Beispiel möchten, dass das Bild doppelt so groß ist:

(var(--m) - var(--f))/var(--m) + var(--f) = 2

Der Wert unseres Skalierungsfaktors --f muss also gleich sein:

var(--m)/(var(--m) - 1)

Bei drei Spalten haben wir 3/2 = 1,5 und das ist der Skalierungsfaktor, den ich im ersten Demo dieses Artikels verwendet habe, weil ich das Bild beim Hovern doppelt so groß machen wollte!

Die gleiche Logik gilt für die Höhenberechnung, und falls wir beide unabhängig voneinander steuern möchten, benötigen wir zwei Skalierungsfaktoren, um sicherzustellen, dass wir beim Hovern eine bestimmte Breite und Höhe haben.

.gallery {
  /* same as before */
   --fw: 1.5; /* controls the scale factor for the width */
   --fh: 1.2; /* controls the scale factor for the height */

  /* same as before */
}

.gallery img:hover{
  width:  calc(var(--w)*var(--fw));
  height: calc(var(--h)*var(--fh));
}

Jetzt kennen Sie alle Geheimnisse, um jede Art von Bildraster mit einem coolen Hover-Effekt zu erstellen und gleichzeitig die gewünschte Größe mit der gerade behandelten Mathematik zu steuern.

Zusammenfassung

In meinem letzten Artikel haben wir ein komplex aussehendes Raster mit wenigen Zeilen CSS erstellt, das die impliziten Grid- und automatischen Platzierungsfunktionen von CSS Grid nutzt. In diesem Artikel haben wir uns auf einige Tricks zur Größenanpassung von CSS Grid verlassen, um ein schickes Raster von Bildern zu erstellen, die beim Hovern zoomen und das Raster entsprechend angepasst wird. All das mit einem vereinfachten Code, der einfach mit CSS-Variablen angepasst werden kann!

Im nächsten Artikel spielen wir mit Formen! Wir werden CSS Grid mit Masken und Clip-Paths kombinieren, um ein schickes Raster von Bildern zu erhalten.