In un articolo precedente, ho esaminato la capacità di CSS Grid di crea layout complessi usando i suoi poteri di posizionamento automatico. Ho fatto un ulteriore passo avanti in un altro articolo che aggiunto un effetto di zoom al passaggio del mouse alle immagini in un layout a griglia. Questa volta, voglio immergermi in un altro tipo di griglia, che funzioni con le forme.
Ad esempio, cosa succede se le immagini non sono perfettamente quadrate ma invece hanno la forma di esagoni o rombi? Avviso spoiler: ce la possiamo fare. In effetti, combineremo le tecniche CSS Grid che abbiamo esaminato e inseriremo alcuni CSS clip-path
ed mask
magia per creare fantasiose griglie di immagini per qualsiasi forma tu possa immaginare!
Iniziamo con un po' di markup
La maggior parte dei layout che esamineremo può sembrare facile da realizzare a prima vista, ma la parte difficile è realizzarli con lo stesso codice HTML. Possiamo usare molti involucri, div
s, e quant'altro, ma l'obiettivo di questo post è utilizzare la stessa e minima quantità di codice HTML e ottenere comunque tutte le diverse griglie che desideriamo. Dopotutto, cos'è il CSS se non un modo per separare lo stile e il markup? Il nostro stile non dovrebbe dipendere dal markup e viceversa.
Detto questo, iniziamo con questo:
<div class="gallery">
<img src="..." alt="...">
<img src="..." alt="...">
<img src="..." alt="...">
<img src="..." alt="...">
<!-- as many times as we want -->
</div>
Un contenitore con le immagini è tutto ciò di cui abbiamo bisogno qui. Niente di più!
Griglia CSS di esagoni
Questo è anche a volte indicato come una griglia "a nido d'ape".
Ci sono già molti altri post sul blog là fuori che mostrano come farlo. Cavolo, io ne ha scritto uno qui su CSS-Tricks! Quell'articolo è ancora buono e approfondisce la creazione di un layout reattivo. Ma per questo caso specifico, faremo affidamento su un approccio CSS molto più semplice.
Per prima cosa, usiamo clip-path
sulle immagini per creare la forma esagonale e le posizioniamo tutte nella stessa area della griglia in modo che si sovrappongano.
.gallery {
--s: 150px; /* controls the size */
display: grid;
}
.gallery > img {
grid-area: 1/1;
width: var(--s);
aspect-ratio: 1.15;
object-fit: cover;
clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0 50%);
}
Niente di speciale ancora. Tutte le immagini sono esagoni e una sopra l'altra. Quindi sembra che tutto ciò che abbiamo sia un singolo elemento dell'immagine a forma esagonale, ma in realtà ce ne sono sette.
Il passaggio successivo consiste nell'applicare una traduzione alle immagini per posizionarle correttamente sulla griglia.
Si noti che vogliamo ancora che una delle immagini rimanga al centro. Il resto viene posizionato attorno ad esso usando CSS translate
e la buona vecchia geometria. Ecco le formule fittizie che ho escogitato per ogni immagine nella griglia:
translate((height + gap)*sin(0deg), (height + gap)*cos(0))
translate((height + gap)*sin(60deg), (height + gap)*cos(60deg))
translate((height + gap)*sin(120deg), (height + gap)*cos(120deg))
translate((height + gap)*sin(180deg), (height + gap)*cos(180deg))
translate((height + gap)*sin(240deg), (height + gap)*cos(240deg))
translate((height + gap)*sin(300deg), (height + gap)*cos(300deg))
Alcuni calcoli e ottimizzazione dopo (saltando quella parte noiosa, giusto?) otteniamo il seguente CSS:
.gallery {
--s: 150px; /* control the size */
--g: 10px; /* control the gap */
display: grid;
}
.gallery > img {
grid-area: 1/1;
width: var(--s);
aspect-ratio: 1.15;
object-fit: cover;
clip-path: polygon(25% 0%, 75% 0%, 100% 50% ,75% 100%, 25% 100%, 0 50%);
transform: translate(var(--_x,0), var(--_y,0));
}
.gallery > img:nth-child(1) { --_y: calc(-100% - var(--g)); }
.gallery > img:nth-child(7) { --_y: calc( 100% + var(--g)); }
.gallery > img:nth-child(3),
.gallery > img:nth-child(5) { --_x: calc(-75% - .87*var(--g)); }
.gallery > img:nth-child(4),
.gallery > img:nth-child(6) { --_x: calc( 75% + .87*var(--g)); }
.gallery > img:nth-child(3),
.gallery > img:nth-child(4) { --_y: calc(-50% - .5*var(--g)); }
.gallery > img:nth-child(5),
.gallery > img:nth-child(6) { --_y: calc( 50% + .5*var(--g)); }
Forse sarà più facile quando arriveremo funzioni trigonometriche reali nei CSS!
Ogni immagine è tradotta dal --_x
ed --_y
variabili basate su tali formule. Solo la seconda immagine (nth-child(2)
) non è definito in nessun selettore perché è quello al centro. Può essere qualsiasi immagine se decidi di utilizzare un ordine diverso. Ecco l'ordine che sto usando:
Con solo poche righe di codice, otteniamo una bella griglia di immagini. A questo, ho aggiunto un piccolo effetto hover alle immagini per rendere le cose più fantasiose.
Indovina un po? Possiamo ottenere un'altra griglia esagonale semplicemente aggiornando alcuni valori.
Se controlli il codice e lo confronti con il precedente noterai che ho semplicemente scambiato i valori all'interno clip-path
e ho cambiato --x
ed --y
. È tutto!
Griglia CSS di rombi
Rombo è una parola così elegante per un quadrato ruotato di 45 gradi.
Stesso HTML, ricordi? Per prima cosa iniziamo definendo una griglia 2×2 di immagini in CSS:
.gallery {
--s: 150px; /* controls the size */
display: grid;
gap: 10px;
grid: auto-flow var(--s) / repeat(2, var(--s));
place-items: center;
}
.gallery > img {
width: 100%;
aspect-ratio: 1;
object-fit: cover;
}
La prima cosa che potrebbe attirare la tua attenzione è il grid
proprietà. È usato in modo piuttosto raro ma è molto utile in quanto è una scorciatoia che ti consente di definire una griglia completa in una dichiarazione. Non è la proprietà più intuitiva, e per non dire leggibile, ma siamo qui per farlo imparare ed scopri nuove cose, quindi usiamolo invece di scrivere tutte le singole proprietà della griglia.
grid: auto-flow var(--s) / repeat(2,var(--s));
/* is equivalent to this: */
grid-template-columns: repeat(2, var(--s));
grid-auto-rows: var(--s);
Questo definisce due colonne uguali a --s
variabile e imposta l'altezza di tutte le righe su --s
anche. Dato che abbiamo quattro immagini, otterremo automaticamente una griglia 2×2.
Ecco un altro modo in cui avremmo potuto scriverlo:
grid-template-columns: repeat(2, var(--s));
grid-template-rows: repeat(2, var(--s));
...che può essere ridotto con il grid
abbreviazione:
grid: repeat(2,var(--s)) / repeat(2,var(--s));
Dopo aver impostato la griglia, la ruotiamo e le immagini con CSS transform
se otteniamo questo:
Nota come li ruoto entrambi di 45deg
, ma nella direzione opposta.
.gallery {
/* etc. */
transform: rotate(45deg);
}
.gallery > img {
/* etc. */
transform: rotate(-45deg);
}
La rotazione delle immagini in direzione negativa impedisce che vengano ruotate con la griglia in modo che rimangano dritte. Ora applichiamo a clip-path
per ritagliare una forma a rombo da loro.
Abbiamo quasi finito! Dobbiamo correggere le dimensioni dell'immagine per farle combaciare. Altrimenti, sono distanziati tra loro fino al punto in cui non sembra una griglia di immagini.
L'immagine si trova all'interno del confine del cerchio verde, che è il cerchio inscritto dell'area della griglia in cui è posizionata l'immagine. Quello che vogliamo è rendere l'immagine più grande per adattarsi al cerchio rosso, che è il cerchio circoscritto dell'area della griglia.
Non preoccuparti, non introdurrò più geometrie noiose. Tutto quello che devi sapere è che la relazione tra il raggio di ogni cerchio è la radice quadrata di 2 (sqrt(2)
). Questo è il valore di cui abbiamo bisogno per aumentare la dimensione delle nostre immagini per riempire l'area. Noi useremo 100%*sqrt(2) = 141%
e basta!
.gallery {
--s: 150px; /* control the size */
display: grid;
grid: auto-flow var(--s) / repeat(2,var(--s));
gap: 10px;
place-items: center;
transform: rotate(45deg);
}
.gallery > img {
width: 141%; /* 100%*sqrt(2) = 141% */
aspect-ratio: 1;
object-fit: cover;
transform: rotate(-45deg);
clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
}
Come la griglia esagonale, possiamo rendere le cose più fantasiose con quel bel effetto di zoomata al passaggio del mouse:
Griglia CSS di forme triangolari
Probabilmente ormai sai che il grande trucco è capire il clip-path
per ottenere le forme che vogliamo. Per questa griglia, ogni elemento ha il suo clip-path
value mentre le ultime due griglie hanno lavorato con una forma coerente. Quindi, questa volta, è come se stessimo lavorando con alcune forme triangolari diverse che si uniscono per formare una griglia rettangolare di immagini.
Li posizioniamo all'interno di una griglia 3×2 con il seguente CSS:
.gallery {
display: grid;
gap: 10px;
grid-template-columns: auto auto auto; /* 3 columns */
place-items: center;
}
.gallery > img {
width: 200px; /* controls the size */
aspect-ratio: 1;
object-fit: cover;
}
/* the clip-path values */
.gallery > img:nth-child(1) { clip-path: polygon(0 0, 50% 0, 100% 100% ,0 100%); }
.gallery > img:nth-child(2) { clip-path: polygon(0 0, 100% 0, 50% 100%); }
.gallery > img:nth-child(3) { clip-path: polygon(50% 0, 100% 0, 100% 100%, 0 100%); }
.gallery > img:nth-child(4) { clip-path: polygon(0 0, 100% 0, 50% 100%, 0 100%); }
.gallery > img:nth-child(5) { clip-path: polygon(50% 0, 100% 100%, 0% 100%); }
.gallery > img:nth-child(6) { clip-path: polygon(0 0, 100% 0 ,100% 100%, 50% 100%); } }
Ecco cosa otteniamo:
Il tocco finale è rendere uguale la larghezza della colonna centrale 0
per eliminare gli spazi tra le immagini. Lo stesso tipo di problema di spaziatura che abbiamo avuto con la griglia a rombi, ma con un approccio diverso per le forme che stiamo usando:
grid-template-columns: auto 0 auto;
Ho dovuto giocherellare con il clip-path
valori per assicurarsi che sembrino combaciare perfettamente come un puzzle. Le immagini originali si sovrappongono quando la colonna centrale ha larghezza zero, ma dopo aver tagliato le immagini, l'illusione è perfetta:
Griglia per pizza CSS
Indovina un po? Possiamo ottenere un'altra griglia interessante semplicemente aggiungendo border-radius
ed overflow
alla nostra griglia o forme triangolari. 🎉
Griglia CSS di pezzi di puzzle
Questa volta giocheremo con i CSS mask
proprietà per far sembrare le immagini come pezzi di un puzzle.
Se non l'hai usato mask
con gradienti CSS, Consiglio vivamente questo altro articolo Ho scritto sull'argomento perché aiuterà con ciò che verrà dopo. Perché i gradienti? Perché è quello che stiamo usando per ottenere le tacche rotonde nelle forme dei pezzi del puzzle.
L'impostazione della griglia dovrebbe essere un gioco da ragazzi ormai, quindi concentriamoci invece sul mask
parte.
Come illustrato nella demo sopra, abbiamo bisogno di due gradienti per creare la forma finale. Un gradiente crea un cerchio (la parte verde) e l'altro crea la curva giusta mentre riempie la parte superiore.
--g: 6px; /* controls the gap */
--r: 42px; /* control the circular shapes */
background:
radial-gradient(var(--r) at left 50% bottom var(--r), green 95%, #0000),
radial-gradient(calc(var(--r) + var(--g)) at calc(100% + var(--g)) 50%, #0000 95%, red)
top/100% calc(100% - var(--r)) no-repeat;
Due variabili controllano la forma. Il --g
variabile non è altro che il gap di griglia. Dobbiamo tenere conto dello spazio vuoto per posizionare correttamente i nostri cerchi in modo che si sovrappongano perfettamente quando l'intero puzzle è assemblato. Il --r
variabile controlla la dimensione delle parti circolari della forma del puzzle.
Ora prendiamo lo stesso CSS e aggiorniamo alcuni valori in esso per creare le altre tre forme:
Abbiamo le forme, ma non i bordi sovrapposti di cui abbiamo bisogno per farli combaciare. Ogni immagine è limitata alla cella della griglia in cui si trova, quindi ha senso il motivo per cui le forme sono un po' confuse al momento:
Abbiamo bisogno di creare un overflow aumentando l'altezza/larghezza delle immagini. Dalla figura sopra, dobbiamo aumentare l'altezza della prima e della quarta immagine mentre aumentiamo la larghezza della seconda e della terza. Probabilmente hai già intuito che dobbiamo aumentarli usando il --r
variabile.
.gallery > img:is(:nth-child(1),:nth-child(4)) {
width: 100%;
height: calc(100% + var(--r));
}
.gallery > img:is(:nth-child(2),:nth-child(3)) {
height: 100%;
width: calc(100% + var(--r));
}
Ci stiamo avvicinando!
Abbiamo creato la sovrapposizione ma, per impostazione predefinita, le nostre immagini si sovrappongono a destra (se aumentiamo la larghezza) o in basso (se aumentiamo l'altezza). Ma non è quello che vogliamo per la seconda e la quarta immagine. La soluzione è usare place-self: end
su quelle due immagini e il nostro codice completo diventa questo:
Ecco un altro esempio in cui sto usando un gradiente conico invece di un gradiente radiale. Questo ci dà pezzi di puzzle triangolari pur mantenendo lo stesso HTML e CSS sottostanti.
Un ultimo! Questa volta sto usando clip-path
e poiché è una proprietà che possiamo animare, otteniamo un bel passaggio del mouse semplicemente aggiornando la proprietà personalizzata che controlla la forma.
Concludendo
Questo è tutto per questa prima parte! Combinando le cose che abbiamo già imparato su CSS Grid con alcune aggiunte clip-path
ed mask
magic, siamo stati in grado di creare layout a griglia con diversi tipi di forme. E abbiamo usato lo stesso markup HTML ogni volta! E il markup stesso non è altro che un contenitore con una manciata di elementi dell'immagine!
Nella seconda parte, esploreremo griglie dall'aspetto più complesso con forme più fantasiose ed effetti al passaggio del mouse.
Ho intenzione di fare la demo dei pannelli di immagini espandibili in cui abbiamo realizzato insieme questo altro articolo:
…e trasformalo in un pannello di immagini a zig-zag! E questo è solo un esempio tra i tanti che scopriremo nel prossimo articolo.