Crea effetti immagine reattivi con gradienti CSS e proporzioni
Pubblicato: 2022-03-10aspect-ratio
recentemente supportata in combinazione con object-fit
fornisce un rimedio a questo mal di testa del passato! Impariamo a usare queste proprietà, oltre a creare un effetto di immagine gradiente reattivo per un tocco in più.Per prepararci ai nostri futuri effetti immagine, imposteremo un componente della scheda che ha un'immagine grande in alto seguita da un titolo e una descrizione. Il problema comune con questa configurazione è che potremmo non avere sempre il controllo perfetto su cosa sia l'immagine e, cosa più importante per il nostro layout, quali siano le sue dimensioni . E mentre questo può essere risolto ritagliando in anticipo, possiamo comunque riscontrare problemi dovuti a contenitori di dimensioni reattive. Una conseguenza sono le posizioni irregolari del contenuto delle carte che risaltano davvero quando si presenta una fila di carte.
Un'altra soluzione precedente oltre al ritaglio potrebbe essere stata quella di passare da un img
inline a un div
vuoto che esisteva solo per presentare l'immagine tramite background-image
. Ho implementato questa soluzione molte volte in passato. Un vantaggio è l'utilizzo di un vecchio trucco per le proporzioni che utilizza un elemento di altezza zero e imposta un valore padding-bottom
. L'impostazione di un valore di riempimento come percentuale produce un valore finale calcolato relativo alla larghezza dell'elemento. Potresti aver utilizzato questa idea anche per mantenere un rapporto 16:9 per gli incorporamenti di video, nel qual caso il valore di riempimento si trova con la formula: 9/16 = 0.5625 * 100% = 56.26%
. Ma esploreremo due moderne proprietà CSS che non implicano calcoli extra, ci danno maggiore flessibilità e consentono anche di mantenere la semantica fornita usando un img
reale invece di un div
vuoto.
Per prima cosa, definiamo la semantica HTML, incluso l'uso di un elenco non ordinato come contenitore delle carte:
<ul class="card-wrapper"> <li class="card"> <img src="" alt=""> <h3>A Super Wonderful Headline</h3> <p>Lorem ipsum sit dolor amit</p> </li> <!-- additional cards --> </ul>
Successivamente, creeremo un insieme minimo di stili di base per il componente .card
. Imposteremo alcuni stili visivi di base per la scheda stessa, un rapido aggiornamento al titolo h3
previsto, quindi gli stili essenziali per iniziare a modellare l'immagine della scheda.
.card { background-color: #fff; border-radius: 0.5rem; box-shadow: 0.05rem 0.1rem 0.3rem -0.03rem rgba(0, 0, 0, 0.45); padding-bottom: 1rem; } .card > :last-child { margin-bottom: 0; } .card h3 { margin-top: 1rem; font-size: 1.25rem; } img { border-radius: 0.5rem 0.5rem 0 0; width: 100%; } img ~ * { margin-left: 1rem; margin-right: 1rem; }
L'ultima regola utilizza il combinatore di pari livello generale per aggiungere un margine orizzontale a qualsiasi elemento che segue l' img
poiché vogliamo che l'immagine stessa sia a filo con i lati della carta.
E i nostri progressi finora ci portano al seguente aspetto della carta:
Infine, creeremo gli stili .card-wrapper
per un layout rapido e reattivo utilizzando la griglia CSS. Questo rimuoverà anche gli stili di elenco predefiniti.
.card-wrapper { list-style: none; padding: 0; margin: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(30ch, 1fr)); grid-gap: 1.5rem; }
Nota : se questa tecnica della griglia non ti è familiare, rivedi la spiegazione nel mio tutorial sulle soluzioni moderne per la griglia a 12 colonne.
Con questo applicato e con tutte le carte contenenti un'immagine con un percorso sorgente valido, i nostri stili .card-wrapper
ci danno il seguente layout:
Come dimostrato nell'immagine di anteprima, questi stili di base non sono sufficienti per contenere correttamente le immagini date le loro dimensioni naturali variabili. Abbiamo bisogno di un metodo per vincolare queste immagini in modo uniforme e coerente.
Abilita Dimensioni immagine uniformi con object-fit
Come notato in precedenza, potresti aver precedentemente effettuato un aggiornamento in questo scenario per modificare le immagini da aggiungere tramite background-image
invece e utilizzare background-size: cover
per gestire correttamente il ridimensionamento dell'immagine. Oppure potresti aver provato a imporre il ritaglio in anticipo (ancora un obiettivo degno poiché qualsiasi riduzione delle dimensioni dell'immagine migliorerà le prestazioni!).
Ora abbiamo la proprietà object-fit
disponibile che consente a un tag img
di fungere da contenitore per l'immagine. Inoltre, viene fornito con un valore di cover
che si traduce in un effetto simile alla soluzione dell'immagine di sfondo, ma con il vantaggio di mantenere la semantica di un'immagine inline. Applichiamolo e vediamo come funziona.
Abbiamo bisogno di accoppiarlo con una dimensione di height
per una guida aggiuntiva su come vogliamo che si comporti il contenitore di immagini (ricorda che avevamo già aggiunto width: 100%
). E useremo la funzione max()
per selezionare 10rem
o 30vh
a seconda di quale sia più grande in un determinato contesto, il che impedisce all'altezza dell'immagine di ridursi troppo su finestre più piccole o quando l'utente ha impostato uno zoom grande.
img { /* ...existing styles */ object-fit: cover; height: max(10rem, 30vh); }
Suggerimento per l'accessibilità bonus : dovresti sempre testare i tuoi layout con uno zoom del 200% e del 400% sul desktop. Sebbene al momento non sia presente una query multimediale di zoom
, funzioni come max()
possono aiutare a risolvere i problemi di layout. Un altro contesto utile per questa tecnica è la spaziatura tra gli elementi.
Con questo aggiornamento, abbiamo decisamente migliorato le cose e il risultato visivo è come se dovessimo utilizzare la vecchia tecnica dell'immagine di sfondo:
Ridimensionamento dell'immagine coerente in modo reattivo con aspect-ratio
Quando si utilizza object-fit
da solo, uno svantaggio è che abbiamo ancora bisogno di impostare alcuni suggerimenti per le dimensioni.
Una prossima proprietà (attualmente disponibile nei browser Chromium) chiamata aspect-ratio
migliorerà la nostra capacità di ridimensionare in modo coerente le immagini.
Usando questa proprietà, possiamo definire un rapporto per ridimensionare l'immagine invece di impostare dimensioni esplicite. Continueremo a usarlo in combinazione con object-fit
per garantire che queste dimensioni influiscano solo sull'immagine come contenitore, altrimenti l'immagine potrebbe apparire distorta.
Ecco la nostra regola dell'immagine completamente aggiornata:
img { border-radius: 0.5rem 0.5rem 0 0; width: 100%; object-fit: cover; aspect-ratio: 4/3; }
Inizieremo con un rapporto immagine di 4 ⁄ 3 per il contesto della nostra carta, ma puoi scegliere qualsiasi rapporto. Ad esempio, 1 ⁄ 1 per un quadrato o 16 ⁄ 9 per incorporamenti video standard.
Ecco le carte aggiornate, anche se probabilmente sarà difficile notare la differenza visiva in questo caso particolare poiché le proporzioni sembrano corrispondere molto all'aspetto che abbiamo ottenuto impostando l' height
per object-fit
solo.
L'impostazione di un "rapporto di aspetto" fa sì che il rapporto venga mantenuto man mano che gli elementi crescono o si restringono, mentre quando si impostano solo "adatta all'oggetto" e "altezza" il rapporto dell'immagine sarà costantemente in mutamento al variare delle dimensioni del contenitore.
“
Aggiunta di effetti reattivi con gradienti e funzioni CSS
OK, ora che sappiamo come impostare immagini di dimensioni costanti, divertiamoci un po' aggiungendo un effetto sfumato!
Il nostro obiettivo con questo effetto è far sembrare che l'immagine stia svanendo nel contenuto della scheda. Potresti essere tentato di avvolgere l'immagine nel suo contenitore per aggiungere il gradiente, ma grazie al lavoro che abbiamo già fatto sul dimensionamento dell'immagine, possiamo capire come farlo in sicurezza sul main .card
.
Il primo passo è definire un gradiente . Utilizzeremo una proprietà personalizzata CSS per aggiungere i colori del gradiente per consentire di scambiare facilmente l'effetto del gradiente, a partire da un blu con un rosa. L'ultimo colore nel gradiente sarà sempre bianco per mantenere la transizione nello sfondo del contenuto della carta e creare il bordo "sfumato".
.card { --card-gradient: #5E9AD9, #E271AD; background-image: linear-gradient( var(--card-gradient), white max(9.5rem, 27vh) ); /* ...existing styles */ }
Ma aspetta: è una funzione CSS max()
? In pendenza? Sì, è possibile, ed è la magia che rende questo gradiente efficace in modo reattivo!
Tuttavia, se dovessi aggiungere uno screenshot, non vedremmo ancora il gradiente che ha alcun effetto sull'immagine. Per questo, dobbiamo inserire la proprietà mix-blend-mode
e in questo scenario utilizzeremo il valore di overlay
:
img { /* ...existing styles */ mix-blend-mode: overlay; }
La proprietà mix-blend-mode
è simile all'applicazione degli stili di fusione dei livelli disponibili in software di manipolazione delle foto come Photoshop. E il valore di overlay
avrà l'effetto di consentire ai toni medi dell'immagine di fondersi con il gradiente dietro di esso, portando al seguente risultato:
Ora, a questo punto, ci affidiamo solo al valore aspect-ratio
per ridimensionare l'immagine. E se ridimensioniamo il contenitore e facciamo ridisporre il layout della scheda, la modifica dell'altezza dell'immagine provoca incoerenze in cui il gradiente diventa bianco.
Quindi aggiungeremo anche una proprietà max-height
che utilizza anche la funzione max()
e contiene valori leggermente maggiori di quelli nel gradiente. Il comportamento risultante è che il gradiente (quasi sempre) si allineerà correttamente con la parte inferiore dell'immagine.
img { /* ...existing styles */ max-height: max(10rem, 30vh); }
È importante notare che l'aggiunta di una 'max-height' altera il comportamento di 'aspect-ratio'. Invece di usare sempre il rapporto esatto, sarà usato solo quando c'è abbastanza spazio allocato dato il nuovo vincolo extra di `max-height`.
“
Tuttavia, aspect-ratio
continueranno comunque a garantire che le immagini vengano ridimensionate in modo coerente, come era il vantaggio rispetto al solo object-fit
. Prova a commentare le aspect-ratio
nella demo finale di CodePen per vedere la differenza che sta facendo tra le dimensioni dei contenitori.
Poiché il nostro obiettivo originale era quello di consentire dimensioni dell'immagine sempre reattive , abbiamo comunque colto nel segno. Per il tuo caso d'uso, potrebbe essere necessario giocherellare con i valori di rapporto e altezza per ottenere l'effetto desiderato.
Alternativa: mix-blend-mode
e aggiunta di un filtro
L'uso della overlay
come valore della mix-blend-mode
era la scelta migliore per l'effetto dissolvenza in bianco che stavamo cercando, ma proviamo un'opzione alternativa per un effetto più drammatico.
Aggiorneremo la nostra soluzione per aggiungere una proprietà personalizzata CSS per il valore mix-blend-mode
e anche per aggiornare i valori di colore per il gradiente:
.card { --card-gradient: tomato, orange; --card-blend-mode: multiply; } img { /* ...existing styles */ mix-blend-mode: var(--card-blend-mode); }
Il valore di multiply
ha un effetto di scurimento sui toni medi, ma mantiene il bianco e il nero così come sono, ottenendo il seguente aspetto:
Anche se abbiamo perso la dissolvenza e ora abbiamo un bordo duro nella parte inferiore dell'immagine, la parte bianca del nostro gradiente è ancora importante per garantire che il gradiente termini prima del contenuto della carta.
Un'ulteriore modifica che possiamo aggiungere è l'uso del filter
e, in particolare, utilizzare la funzione grayscale()
per rimuovere i colori dell'immagine e quindi fare in modo che il gradiente sia l'unica fonte di colorazione dell'immagine.
img { /* ...existing styles */ filter: grayscale(100); }
L'utilizzo del valore di scala di grayscale(100)
comporta la rimozione completa dei colori naturali dell'immagine e la sua trasformazione in bianco e nero. Ecco l'aggiornamento per il confronto con lo screenshot precedente del suo effetto quando si utilizza il nostro gradiente arancione con multiply
:
Usa aspect-ratio
come miglioramento progressivo
Come accennato in precedenza, attualmente aspect-ratio
sono supportate solo nell'ultima versione dei browser Chromium (Chrome ed Edge). Tuttavia, tutti i browser supportano object-fit
e questo, insieme ai nostri vincoli di height
, si traduce in un risultato meno ideale ma comunque accettabile, visto qui per Safari:
Senza il funzionamento delle aspect-ratio
, il risultato qui è che alla fine l'altezza dell'immagine è limitata, ma le dimensioni naturali di ciascuna immagine portano comunque a una certa variazione tra le altezze dell'immagine della scheda. Potresti invece voler cambiare per aggiungere max-height
o utilizzare di nuovo la funzione max()
per rendere max-height
più reattiva su carte di dimensioni diverse.
Estendere gli effetti gradiente
Poiché abbiamo definito le interruzioni di colore del gradiente come proprietà personalizzata CSS, abbiamo accesso pronto per modificarle in contesti diversi. Ad esempio, potremmo modificare il gradiente per evidenziare più fortemente uno dei colori se la scheda è posizionata al passaggio del mouse o ha uno dei suoi figli a fuoco.
Innanzitutto, aggiorneremo ogni scheda h3
in modo che contenga un collegamento, ad esempio:
<h3><a href="">A Super Wonderful Headline</a></h3>
Quindi, possiamo utilizzare uno dei nostri più recenti selettori disponibili — :focus-within
— per modificare il gradiente della scheda quando il collegamento è a fuoco. Per una copertura aggiuntiva delle possibili interazioni, lo accoppieremo con :hover
. E riutilizzeremo la nostra idea max()
per assegnare un singolo colore che occupi la copertura della porzione dell'immagine della scheda. Lo svantaggio di questo particolare effetto è che le interruzioni del gradiente e i cambi di colore non sono animabili in modo affidabile, ma lo saranno presto grazie a CSS Houdini.
Per aggiornare il colore e aggiungere il nuovo stop colore, dobbiamo solo riassegnare il valore di --card-gradient
all'interno di questa nuova regola:
.card:focus-within, .card:hover { --card-gradient: #24a9d5 max(8.5rem, 20vh); }
I nostri valori max()
sono inferiori all'originale in uso per white
per mantenere il bordo sfumato. Se usassimo gli stessi valori, incontrerebbe il white
e creerebbe una netta separazione del righello.
Durante la creazione di questa demo, inizialmente ho provato un effetto che utilizzava la transform
con scale
per un effetto di ingrandimento. Ma ho scoperto che a causa dell'applicazione della mix-blend-mode
, il browser non ridipingeva costantemente l'immagine causando uno sgradevole sfarfallio. Ci saranno sempre dei compromessi nel richiedere al browser di eseguire effetti e animazioni solo CSS e, sebbene sia molto interessante quello che possiamo fare, è sempre meglio controllare l'impatto sulle prestazioni dei tuoi effetti.
Divertiti a sperimentare!
I moderni CSS ci hanno fornito alcuni fantastici strumenti per aggiornare i nostri toolkit di progettazione web, con aspect-ratio
che è l'ultima aggiunta. Quindi vai avanti e sperimenta con object-fit
, aspect-ratio
e aggiungendo funzioni come max()
nei tuoi gradienti per alcuni divertenti effetti reattivi! Assicurati solo di ricontrollare le cose su più browser (per ora!) e su diverse finestre e dimensioni dei contenitori.
Ecco la CodePen che include le caratteristiche e gli effetti che abbiamo recensito oggi:
Cerchi di più? Assicurati di controllare la nostra Guida CSS qui su Smashing →