Creați efecte de imagine receptive cu degrade CSS și raport de aspect

Publicat: 2022-03-10
Rezumat rapid ↬ O problemă clasică în CSS este menținerea raportului de aspect al imaginilor între componentele conexe, cum ar fi cardurile. Proprietatea aspect-ratio nou acceptată în combinație cu object-fit oferă un remediu pentru această durere de cap a trecutului! Să învățăm să folosim aceste proprietăți, pe lângă crearea unui efect de imagine gradient receptiv pentru un plus de fler.

Pentru a ne pregăti pentru viitoarele efecte de imagine, vom configura o componentă de card care are o imagine mare în partea de sus, urmată de un titlu și descriere. Problema comună cu această configurație este că este posibil să nu avem întotdeauna controlul perfect asupra a ceea ce este imaginea și, mai important, pentru aspectul nostru, care sunt dimensiunile acesteia. Și, deși acest lucru poate fi rezolvat prin decuparea din timp, putem întâmpina probleme din cauza containerelor de dimensiuni adecvate. O consecință este pozițiile inegale ale conținutului cardului, care iese cu adevărat în evidență atunci când prezentați un rând de cărți.

O altă soluție anterioară, pe lângă decuparea, ar fi putut fi schimbarea de la o imagine img la un div gol care exista doar pentru a prezenta imaginea prin imaginea background-image . Am implementat această soluție de multe ori în trecut. Un avantaj pe care îl are este utilizarea unui truc mai vechi pentru raportul de aspect, care utilizează un element de înălțime zero și setează o valoare padding-bottom . Setarea unei valori de umplutură ca procent are ca rezultat o valoare finală calculată care este relativă la lățimea elementului. Este posibil să fi folosit și această idee pentru a menține un raport de 16:9 pentru încorporarea videoclipurilor, caz în care valoarea de umplutură se găsește cu formula: 9/16 = 0.5625 * 100% = 56.26% . Dar vom explora două proprietăți CSS moderne care nu implică matematică suplimentară, ne oferă mai multă flexibilitate și, de asemenea, permit păstrarea semanticii furnizate prin utilizarea unui img real în loc de un div gol.

Mai întâi, să definim semantica HTML, inclusiv utilizarea unei liste neordonate ca container pentru carduri:

 <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>

În continuare, vom crea un set minim de stiluri de bază pentru componenta .card . Vom seta câteva stiluri vizuale de bază pentru cardul în sine, o actualizare rapidă a titlului h3 așteptat, apoi stiluri esențiale pentru a începe să stilăm imaginea cardului.

 .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; }

Ultima regulă folosește combinatorul general de frați pentru a adăuga o marjă orizontală oricărui element care urmează img , deoarece dorim ca imaginea în sine să fie la același nivel cu părțile laterale ale cardului.

Și progresul nostru de până acum ne conduce la următoarea apariție a cărților:

Un card cu stilurile de bază descrise anterior aplicate și care include o imagine din Unsplash a unui desert pe o farfurie mică lângă o băutură fierbinte într-o cană
Un card cu stilurile de bază descrise anterior aplicate și care include o imagine de la Unsplash a unui desert pe o farfurie mică lângă o băutură fierbinte într-o cană. (Previzualizare mare)

În cele din urmă, vom crea stilurile .card-wrapper pentru un aspect rapid receptiv folosind grila CSS. Acest lucru va elimina și stilurile implicite ale listei.

 .card-wrapper { list-style: none; padding: 0; margin: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(30ch, 1fr)); grid-gap: 1.5rem; }

Notă : Dacă această tehnică de grilă nu vă este familiară, consultați explicația din tutorialul meu despre soluțiile moderne pentru grila cu 12 coloane.

Cu acest lucru aplicat și cu toate cardurile care conțin o imagine cu o cale sursă validă, stilurile noastre .card-wrapper ne oferă următorul aspect:

Trei cărți sunt afișate într-un rând datorită stilurilor de aspect aplicate. Fiecare card are o imagine unică care are diferite raporturi de aspect naturale, ultima carte având o imagine orientată vertical care este de peste două ori înălțimea celorlalte imagini de card.
Trei cărți sunt afișate într-un rând datorită stilurilor de aspect aplicate. Fiecare card are o imagine unică, care are diferite raporturi de aspect naturale, ultimul card având o imagine orientată vertical, care este de peste două ori înălțimea celorlalte imagini de card. (Previzualizare mare)

După cum se demonstrează în imaginea de previzualizare, aceste stiluri de bază nu sunt suficiente pentru a conține imaginile în mod corespunzător, având în vedere dimensiunile lor naturale diferite. Avem nevoie de o metodă pentru a constrânge aceste imagini în mod uniform și consecvent.

Mai multe după săritură! Continuați să citiți mai jos ↓

Activați Dimensiunile uniforme ale imaginii cu object-fit

După cum sa menționat mai devreme, este posibil să fi efectuat anterior o actualizare în acest scenariu pentru a modifica imaginile care urmează să fie adăugate prin background-image și ați folosit background-size: cover pentru a gestiona frumos redimensionarea imaginii. Sau poate ați încercat să impuneți tăierea din timp (încă un obiectiv demn, deoarece orice reducere a dimensiunii imaginii va îmbunătăți performanța!).

Acum, avem disponibilă proprietatea object-fit care permite unei etichete img să acționeze ca container pentru imagine. Și, vine și cu o valoare de cover , care are ca rezultat un efect similar cu soluția de imagine de fundal, dar cu bonusul de a păstra semantica unei imagini în linie. Să-l aplicăm și să vedem cum funcționează.

Trebuie să-l împerechem cu o dimensiune de height pentru îndrumare suplimentară cu privire la modul în care dorim să se comporte containerul de imagine (reamintim că am adăugat deja width: 100% ). Și vom folosi funcția max() pentru a selecta fie 10rem , fie 30vh în funcție de care este mai mare într-un context dat, ceea ce împiedică înălțimea imaginii să se micșoreze prea mult pe ferestre mai mici sau când utilizatorul a setat un zoom mare.

 img { /* ...existing styles */ object-fit: cover; height: max(10rem, 30vh); }

Sfat de accesibilitate bonus : ar trebui să testați întotdeauna machetele cu zoom de 200% și 400% pe desktop. Deși în prezent nu există o interogare media zoom , funcții precum max() pot ajuta la rezolvarea problemelor de aspect. Un alt context pe care această tehnică este utilă este distanța dintre elemente.

Cu această actualizare, am îmbunătățit cu siguranță lucrurile, iar rezultatul vizual este ca și cum am folosi tehnica mai veche a imaginii de fundal:

Imaginile cu trei carduri par acum să aibă o înălțime uniformă, iar conținutul imaginii este centrat în imagine ca și cum ar fi un container
Imaginile cu trei carduri par acum să aibă o înălțime uniformă, iar conținutul imaginii este centrat în imagine ca și cum ar fi un container. (Previzualizare mare)

Dimensiunea imaginii în mod receptiv și consistentă cu aspect-ratio

Când folosiți object-fit în sine, un dezavantaj este că mai trebuie să setăm câteva indicii de dimensiune.

O proprietate viitoare (disponibilă în prezent în browserele Chromium) numită aspect-ratio va îmbunătăți capacitatea noastră de a dimensiona în mod constant imaginile.

Folosind această proprietate, putem defini un raport pentru a redimensiona imaginea în loc să setăm dimensiuni explicite. Vom continua să-l folosim în combinație cu object-fit pentru a ne asigura că aceste dimensiuni afectează doar imaginea ca container, în caz contrar, imaginea ar putea apărea distorsionată.

Iată regula noastră completă pentru imagini actualizate:

 img { border-radius: 0.5rem 0.5rem 0 0; width: 100%; object-fit: cover; aspect-ratio: 4/3; }

Vom începe cu un raport de imagine de 43 pentru contextul cardului nostru, dar puteți alege orice raport. De exemplu, 11 pentru un pătrat sau 169 pentru încorporarea video standard.

Iată cardurile actualizate, deși probabil va fi dificil de observat diferența vizuală în acest caz particular, deoarece raportul de aspect se întâmplă să se potrivească îndeaproape cu aspectul pe care l-am obținut prin setarea height numai pentru object-fit .

Imaginile cu trei carduri au dimensiuni identice de lățime și înălțime, care sunt ușor diferite față de soluția anterioară de adaptare la obiect
Imaginile cu trei carduri au dimensiuni identice de lățime și înălțime, care sunt ușor diferite față de soluția anterioară de adaptare la obiect. (Previzualizare mare)

Setarea unui „raport de aspect” are ca rezultat menținerea raportului pe măsură ce elementele cresc sau se micșorează, în timp ce atunci când setați doar „potrivire obiect” și „înălțime”, raportul imaginii va fi în mod constant în flux pe măsură ce dimensiunile containerului se schimbă.

Adăugarea de efecte receptive cu degrade și funcții CSS

OK, acum că știm cum să setăm imagini de dimensiuni constante, să ne distrăm puțin cu ele adăugând un efect de gradient!

Scopul nostru cu acest efect este să facem să pară ca și cum imaginea se estompează în conținutul cardului. S-ar putea să fiți tentat să înfășurați imaginea în propriul container pentru a adăuga gradient, dar datorită muncii pe care am făcut-o deja cu privire la dimensionarea imaginii, putem găsi cum să o facem în siguranță pe .card principal .

Primul pas este definirea unui gradient . Vom folosi o proprietate personalizată CSS pentru a adăuga culorile gradientului pentru a permite schimbarea cu ușurință a efectului de gradient, începând cu albastru la roz. Ultima culoare din gradient va fi întotdeauna albă pentru a menține tranziția în fundalul conținutului cardului și pentru a crea marginea „pene”.

 .card { --card-gradient: #5E9AD9, #E271AD; background-image: linear-gradient( var(--card-gradient), white max(9.5rem, 27vh) ); /* ...existing styles */ }

Dar așteptați - este o funcție CSS max() ? Într-un gradient? Da, este posibil și magia este cea care face ca acest gradient să răspundă eficient!

Cu toate acestea, dacă ar fi să adaug o captură de ecran, nu am vedea de fapt că gradientul are vreun efect asupra imaginii. Pentru aceasta, trebuie să introducem proprietatea mix-blend-mode și, în acest scenariu, vom folosi valoarea de overlay :

 img { /* ...existing styles */ mix-blend-mode: overlay; }

Proprietatea mix-blend-mode este similară cu aplicarea stilurilor de amestecare a straturilor disponibile în software-ul de manipulare a fotografiilor, cum ar fi Photoshop. Și valoarea de overlay va avea efectul de a permite tonurilor medii din imagine să se amestece cu gradientul din spatele acesteia, ducând la următorul rezultat:

Fiecare imagine de card are un efect de amestecare de gradient care începe cu un albastru deschis în partea de sus, care se amestecă într-un roz roșcat și apoi se termină prin transformarea într-un alb înainte de restul conținutului textului cardului.
Fiecare imagine de card are un efect de amestecare de gradient care începe cu un albastru deschis în partea de sus, care se amestecă într-un roz roșcat și apoi se termină prin transformarea într-un alb înainte de restul conținutului textului cardului. (Previzualizare mare)

Acum, în acest moment, ne bazăm doar pe valoarea aspect-ratio pentru a redimensiona imaginea. Și dacă redimensionăm containerul și facem ca aspectul cardului să revină, schimbarea înălțimii imaginii provoacă inconsecvențe în cazul în care gradientul devine alb.

Deci vom adăuga și o proprietate max-height care folosește și funcția max() și conține valori puțin mai mari decât cele din gradient. Comportamentul rezultat este că gradientul se va alinia corect (aproape întotdeauna) cu partea de jos a imaginii.

 img { /* ...existing styles */ max-height: max(10rem, 30vh); }

Este important de reținut că adăugarea unei „înălțimi maxime” modifică comportamentul „raportului de aspect”. În loc să se folosească întotdeauna raportul exact, acesta va fi folosit numai atunci când există suficient spațiu alocat, având în vedere noua constrângere suplimentară a „înălțimii maxime”.

Cu toate acestea, aspect-ratio va continua să asigure redimensionarea în mod constant a imaginilor, așa cum a fost beneficiul față de numai object-fit . Încercați să comentați aspect-ratio în demonstrația finală CodePen pentru a vedea diferența pe care o face în funcție de dimensiunile containerelor.

Întrucât obiectivul nostru inițial a fost să permitem dimensiunile imaginii receptive în mod constant , am ajuns în continuare la obiectiv. Pentru propriul dvs. caz de utilizare, poate fi necesar să vă jucați cu valorile raportului și al înălțimii pentru a obține efectul dorit.

Alternativ: mix-blend-mode și adăugarea unui filtru

Folosirea overlay ca valoare a mix-blend-mode a fost cea mai bună alegere pentru efectul de estompare în alb pe care îl căutam, dar haideți să încercăm o opțiune alternativă pentru un efect mai dramatic.

Vom actualiza soluția noastră pentru a adăuga o proprietate personalizată CSS pentru valoarea mix-blend-mode și, de asemenea, vom actualiza valorile de culoare pentru gradient:

 .card { --card-gradient: tomato, orange; --card-blend-mode: multiply; } img { /* ...existing styles */ mix-blend-mode: var(--card-blend-mode); }

Valoarea de multiply are un efect de întunecare a tonurilor medii, dar păstrează albul și negru așa cum este, rezultând următorul aspect:

Fiecare imagine de card are o nuanță portocalie puternică din noul gradient care începe de la un roșu-portocaliu la portocaliu pur. Zonele albe sunt încă albe, iar zonele negre sunt încă negre
Fiecare imagine de card are o nuanță portocalie puternică din noul gradient care începe de la un roșu-portocaliu la portocaliu pur. Zonele albe sunt încă albe, iar zonele negre sunt încă negre. (Previzualizare mare)

Deși am pierdut decolorarea și acum avem o margine dură în partea de jos a imaginii, partea albă a gradientului nostru este încă importantă pentru a ne asigura că gradientul se termină înainte de conținutul cardului.

O modificare suplimentară pe care o putem adăuga este utilizarea filter și, în special, utilizarea funcției grayscale() pentru a elimina culorile imaginii și, prin urmare, pentru ca gradientul să fie singura sursă de colorare a imaginii.

 img { /* ...existing styles */ filter: grayscale(100); }

Utilizarea valorii tonurilor de grayscale(100) are ca rezultat eliminarea completă a culorilor naturale ale imaginii și transformarea acesteia în alb-negru. Iată actualizarea pentru comparație cu captura de ecran anterioară a efectului său atunci când folosiți gradientul nostru portocaliu cu multiply :

Acum, fiecare imagine de card are în continuare gradient portocaliu, dar toate celelalte culori sunt eliminate și înlocuite cu nuanțe de gri
Acum, fiecare imagine de card are în continuare gradient portocaliu, dar toate celelalte culori sunt eliminate și înlocuite cu nuanțe de gri. (Previzualizare mare)

Utilizați aspect-ratio ca îmbunătățire progresivă

După cum sa menționat anterior, în prezent aspect-ratio este acceptat numai în cea mai recentă versiune a browserelor Chromium (Chrome și Edge). Cu toate acestea, toate browserele acceptă object-fit și asta, împreună cu constrângerile noastre de height , are ca rezultat un rezultat mai puțin ideal, dar totuși acceptabil, văzut aici pentru Safari:

Înălțimea imaginii cardului este limitată, dar fiecare card are o înălțime realizată ușor diferită
Înălțimea imaginii cardului este limitată, dar fiecare card are o înălțime realizată ușor diferită. (Previzualizare mare)

Fără funcționarea aspect-ratio , rezultatul aici este că în cele din urmă înălțimea imaginii este limitată, dar dimensiunile naturale ale fiecărei imagini conduc încă la o oarecare variație între înălțimile imaginii cardului. Poate doriți să treceți la adăugarea unei max-height sau să utilizați din nou funcția max() pentru a face o max-height mai receptivă la diferite dimensiuni de card.

Extinderea efectelor de gradient

Deoarece am definit opririle de culoare gradient ca o proprietate personalizată CSS, avem acces facil pentru a le modifica în diferite contexte. De exemplu, am putea schimba gradientul pentru a prezenta mai puternic una dintre culori dacă cardul este plasat cu mouse-ul sau are unul dintre copiii săi focalizat.

În primul rând, vom actualiza fiecare card h3 pentru a conține un link, cum ar fi:

 <h3><a href="">A Super Wonderful Headline</a></h3>

Apoi, putem folosi unul dintre cele mai noi selectoare disponibile — :focus-within — pentru a modifica gradientul cardului atunci când legătura este focalizată. Pentru o acoperire suplimentară a posibilelor interacțiuni, vom cupla acest lucru cu :hover . Și, vom reutiliza ideea noastră max() pentru a atribui o singură culoare pentru a prelua acoperirea porțiunii de imagine a cardului. Dezavantajul acestui efect special este că opririle gradientului și schimbările de culoare nu pot fi animate în mod fiabil - dar vor fi în curând datorită CSS Houdini.

Pentru a actualiza culoarea și a adăuga noua oprire de culoare, trebuie doar să reatribuim valoarea --card-gradient în cadrul acestei noi reguli:

 .card:focus-within, .card:hover { --card-gradient: #24a9d5 max(8.5rem, 20vh); }

Valorile noastre max() sunt mai mici decât originalul utilizat pentru white pentru a menține marginea pene. Dacă am folosi aceleași valori, s-ar întâlni white și ar crea o separare clară a dreptului.

În crearea acestei demonstrații, am încercat inițial un efect care folosea transform cu scale pentru un efect de mărire. Dar am descoperit că, din cauza mix-blend-mode aplicat, browserul nu va revopsi în mod constant imaginea, ceea ce a provocat o pâlpâire neplăcută. Vor exista întotdeauna compromisuri în a solicita browserului să efectueze numai efecte și animații CSS și, deși este foarte bine ceea ce putem face, este întotdeauna cel mai bine să verificați impactul asupra performanței al efectelor dvs.

Distrează-te experimentând!

CSS modern ne-a oferit câteva instrumente minunate pentru actualizarea setului nostru de instrumente pentru design web, aspect-ratio fiind cea mai recentă adăugare. Așa că mergeți mai departe și experimentați cu object-fit , aspect-ratio și adăugarea de funcții precum max() în gradienții dvs. pentru niște efecte distractive de răspuns! Asigurați-vă că verificați din nou lucrurile pe mai multe browsere (deocamdată!) și în diferite ferestre de vizualizare și dimensiuni de containere.

Iată CodePen-ul, inclusiv caracteristicile și efectele pe care le-am analizat astăzi:

Vedeți Pen [Efecte de imagine receptive cu degrade CSS și raport de aspect](https://codepen.io/smashingmag/pen/WNoERXo) de Stephanie Eckles.

Vedeți Efectele de imagine receptive cu stiloul cu degrade CSS și raportul de aspect de Stephanie Eckles.

Cauți mai mult? Asigurați-vă că consultați Ghidul nostru CSS aici pe Smashing →