Twórz responsywne efekty graficzne za pomocą gradientów CSS i proporcji

Opublikowany: 2022-03-10
Szybkie podsumowanie ↬ Klasycznym problemem w CSS jest utrzymanie proporcji obrazów w powiązanych ze sobą komponentach, takich jak karty. Nowo obsługiwana właściwość aspect-ratio w połączeniu z object-fit zapewnia remedium na ten ból głowy z przeszłości! Nauczmy się korzystać z tych właściwości, a także tworzyć responsywny efekt gradientu obrazu, aby uzyskać dodatkowy styl.

Aby przygotować się na nasze przyszłe efekty graficzne, skonfigurujemy komponent karty, który ma duży obraz u góry, a następnie nagłówek i opis. Częstym problemem związanym z tą konfiguracją jest to, że nie zawsze możemy mieć idealną kontrolę nad tym, czym jest obraz, a co ważniejsze nad naszym układem, nad jego wymiarami . I chociaż można to rozwiązać, przycinając z wyprzedzeniem, nadal możemy napotkać problemy z powodu responsywnych kontenerów. Konsekwencją są nierówne pozycje zawartości kart, które naprawdę wyróżniają się, gdy prezentujesz rząd kart.

Inne wcześniejsze rozwiązanie oprócz kadrowania mogło polegać na zamianie wbudowanego img na pusty element div , który istniał tylko po to, aby prezentować obraz za pośrednictwem obrazu background-image . W przeszłości wielokrotnie wdrażałem to rozwiązanie. Jedną z zalet tego rozwiązania jest użycie starszej sztuczki dla współczynnika proporcji, która wykorzystuje element o zerowej wysokości i ustawia padding-bottom . Ustawienie wartości dopełnienia jako wartości procentowej skutkuje ostateczną obliczoną wartością, która jest zależna od szerokości elementu. Być może wykorzystałeś ten pomysł, aby zachować proporcje 16:9 dla osadzonych filmów wideo, w którym to przypadku wartość dopełnienia jest określana wzorem: 9/16 = 0.5625 * 100% = 56.26% . Ale zamierzamy zbadać dwie nowoczesne właściwości CSS , które nie wymagają dodatkowej matematyki, dają nam większą elastyczność, a także pozwalają zachować semantykę zapewnianą przez użycie prawdziwego img zamiast pustego div .

Najpierw zdefiniujmy semantykę HTML, w tym użycie nieuporządkowanej listy jako kontenera kart:

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

Następnie utworzymy minimalny zestaw stylów bazowych dla komponentu .card . Ustawimy kilka podstawowych stylów wizualnych dla samej karty, szybką aktualizację oczekiwanego nagłówka h3 , a następnie podstawowe style, aby zacząć stylizować obraz karty.

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

Ostatnia zasada wykorzystuje ogólny kombinator rodzeństwa , aby dodać poziomy margines do dowolnego elementu następującego po img , ponieważ chcemy, aby sam obraz był wyrównany z bokami karty.

A nasze dotychczasowe postępy prowadzą nas do następującego wyglądu karty:

Zastosowano jedną kartę z wcześniej opisanymi stylami bazowymi i zawierającą obraz z Unsplash deseru na małym talerzu obok gorącego napoju w kubku
Zastosowano jedną kartę z wcześniej opisanymi stylami bazowymi, zawierającą obraz z Unsplash deseru na małym talerzu obok gorącego napoju w kubku. (duży podgląd)

Na koniec utworzymy style .card-wrapper , aby szybko responsywny układ za pomocą siatki CSS. Spowoduje to również usunięcie domyślnych stylów list.

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

Uwaga : Jeśli ta technika siatki jest ci nieznana, przejrzyj wyjaśnienie w moim samouczku na temat nowoczesnych rozwiązań dla siatki 12-kolumnowej.

Po zastosowaniu tego i wszystkich kartach zawierających obraz z prawidłową ścieżką źródłową nasze style .card-wrapper dają nam następujący układ:

Trzy karty są wyświetlane w rzędzie ze względu na zastosowane style układu opakowania kart. Każda karta ma unikalny obraz, który ma różne naturalne proporcje, a ostatnia karta ma pionowo zorientowany obraz, który jest ponad dwukrotnie wyższy od innych obrazów kart
Trzy karty są wyświetlane w rzędzie ze względu na zastosowane style układu opakowania kart. Każda karta ma unikalny obraz, który ma różne naturalne proporcje, przy czym ostatnia karta ma pionowo zorientowany obraz, który jest ponad dwukrotnie wyższy niż obrazy innych kart. (duży podgląd)

Jak pokazano na obrazie podglądu, te style linii bazowych nie są wystarczające, aby prawidłowo zawierać obrazy, biorąc pod uwagę ich różne naturalne wymiary. Potrzebujemy metody, aby ograniczyć te obrazy w sposób jednolity i spójny.

Więcej po skoku! Kontynuuj czytanie poniżej ↓

Włącz jednolite rozmiary obrazu z object-fit

Jak wspomniano wcześniej, być może wcześniej dokonałeś aktualizacji w tym scenariuszu, aby zmienić obrazy, które mają zostać dodane za pomocą background-image i użyłeś background-size: cover , aby ładnie obsłużyć zmianę rozmiaru obrazu. Lub być może próbowałeś wymusić przycinanie z wyprzedzeniem (nadal jest to godny cel, ponieważ każde zmniejszenie rozmiaru obrazu poprawi wydajność!).

Teraz mamy dostępną właściwość object-fit , która umożliwia img pełnienie roli kontenera obrazu. Ma też wartość cover , która daje podobny efekt jak rozwiązanie z obrazem tła, ale z bonusem zachowania semantyki obrazu w wierszu. Zastosujmy to i zobaczmy, jak to działa.

Musimy sparować go z wymiarem height , aby uzyskać dodatkowe wskazówki dotyczące zachowania kontenera obrazu (przypomnijmy, że dodaliśmy już width: 100% ). Zamierzamy użyć funkcji max() , aby wybrać 10rem lub 30vh w zależności od tego, która wartość jest większa w danym kontekście, co zapobiega zbytniemu zmniejszeniu się wysokości obrazu na mniejszych rzutniach lub gdy użytkownik ustawił duży zoom.

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

Dodatkowa wskazówka dotycząca ułatwień dostępu : Zawsze powinieneś testować swoje układy z 200% i 400% powiększeniem na pulpicie. Chociaż obecnie nie ma zapytania o media zoom , funkcje takie jak max() mogą pomóc w rozwiązaniu problemów z układem. Innym kontekstem, w którym ta technika jest przydatna, są odstępy między elementami.

Dzięki tej aktualizacji zdecydowanie poprawiliśmy to, a efekt wizualny wygląda tak, jakbyśmy używali starszej techniki obrazowania tła:

Obrazy z trzema kartami wydają się teraz mieć jednakową wysokość, a zawartość obrazu jest wyśrodkowana w obrazie, tak jakby był pojemnikiem
Obrazy z trzema kartami wydają się teraz mieć jednakową wysokość, a zawartość obrazu jest wyśrodkowana w obrazie, tak jakby była pojemnikiem. (duży podgląd)

Elastycznie spójny rozmiar obrazu z aspect-ratio

Podczas korzystania z samego object-fit , jedną wadą jest to, że nadal musimy ustawić pewne wskazówki dotyczące wymiarów.

Nadchodząca właściwość (obecnie dostępna w przeglądarkach Chromium) o nazwie aspect-ratio zwiększy naszą zdolność do spójnego rozmiaru obrazów.

Korzystając z tej właściwości, możemy zdefiniować współczynnik zmiany rozmiaru obrazu zamiast określania wyraźnych wymiarów. Będziemy nadal używać go w połączeniu z object-fit aby zapewnić, że te wymiary będą miały wpływ tylko na obraz jako kontener, w przeciwnym razie obraz może wyglądać na zniekształcony.

Oto nasza w pełni zaktualizowana zasada dotycząca obrazów:

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

Zaczniemy od proporcji obrazu 43 dla naszego kontekstu karty, ale możesz wybrać dowolny stosunek. Na przykład 1 × 1 dla kwadratu lub 16 × 9 dla standardowych osadzonych filmów wideo.

Oto zaktualizowane karty, chociaż prawdopodobnie trudno będzie zauważyć różnicę wizualną w tym konkretnym przypadku, ponieważ proporcje są bardzo zbliżone do wyglądu, który osiągnęliśmy, ustawiając height tylko dla object-fit .

Obrazy składające się z trzech kart mają identyczne wymiary szerokości i wysokości, które nieznacznie różnią się od poprzedniego rozwiązania dopasowywania obiektów
Obrazy składające się z trzech kart mają identyczne wymiary szerokości i wysokości, które nieco różnią się od poprzedniego rozwiązania dopasowywania obiektów. (duży podgląd)

Ustawienie „współczynnika proporcji” powoduje, że proporcje są utrzymywane w miarę wzrostu lub kurczenia się elementów, podczas gdy ustawienie tylko „dopasowania obiektu” i „wysokości” powoduje, że proporcje obrazu będą stale się zmieniać wraz ze zmianą wymiarów pojemnika.

Dodawanie responsywnych efektów za pomocą gradientów i funkcji CSS

OK, teraz, gdy wiemy, jak ustawić obrazy o spójnych rozmiarach, bawmy się z nimi, dodając efekt gradientu!

Naszym celem z tym efektem jest sprawienie, by obraz zanikał w treści karty. Możesz pokusić się o zawinięcie obrazu we własny kontener, aby dodać gradient, ale dzięki pracy, którą już wykonaliśmy nad rozmiarem obrazu, możemy wypracować, jak bezpiecznie to zrobić na głównej .card .

Pierwszym krokiem jest zdefiniowanie gradientu . Użyjemy niestandardowej właściwości CSS, aby dodać kolory gradientu, aby umożliwić łatwą zamianę efektu gradientu, zaczynając od niebieskiego do różowego. Ostatni kolor w gradiencie będzie zawsze biały, aby zachować przejście do tła zawartości karty i stworzyć „pierzastą” krawędź.

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

Ale czekaj — czy to funkcja CSS max() ? W gradiencie? Tak, to możliwe i to magia sprawia, że ​​ten gradient jest skuteczny!

Gdybym jednak dodał zrzut ekranu, nie zobaczylibyśmy jeszcze, jak gradient ma jakikolwiek wpływ na obraz. W tym celu musimy wprowadzić właściwość mix-blend-mode , a w tym scenariuszu użyjemy wartości overlay :

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

Właściwość mix-blend-mode jest podobna do stosowania stylów mieszania warstw dostępnych w oprogramowaniu do obróbki zdjęć, takim jak Photoshop. A wartość overlay spowoduje, że średnie tony obrazu zmieszają się z gradientem za nim, prowadząc do następującego wyniku:

Każdy obraz karty ma efekt mieszania gradientu, który zaczyna się od jasnoniebieskiego u góry, przechodzi w czerwonawo-różowy, a następnie wtapia się w biel przed resztą tekstu karty
Każdy obraz karty ma efekt mieszania gradientu, który zaczyna się od jasnoniebieskiego u góry, przechodzi w czerwonawy róż, a następnie wtapia się w biel przed resztą tekstu karty. (duży podgląd)

Teraz, w tym momencie, polegamy na samej wartości aspect-ratio , aby zmienić rozmiar obrazu. A jeśli zmienimy rozmiar kontenera i spowodujemy zmianę układu karty, zmieniająca się wysokość obrazu spowoduje niespójności w miejscu, w którym gradient zanika do bieli.

Dodamy więc również właściwość max-height , która również używa funkcji max() i zawiera wartości nieco większe niż te w gradiencie. Efektem tego jest to, że gradient (prawie zawsze) będzie wyrównany z dołem obrazu.

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

Należy zauważyć, że dodanie „max-height” zmienia zachowanie „współczynnika proporcji”. Zamiast zawsze używać dokładnego współczynnika, będzie on używany tylko wtedy, gdy jest wystarczająco dużo miejsca, biorąc pod uwagę nowe dodatkowe ograniczenie `max-height`.

Jednak aspect-ratio nadal będzie zapewniał spójną zmianę rozmiaru obrazów, co było zaletą w porównaniu tylko object-fit . Spróbuj skomentować aspect-ratio w końcowej wersji demonstracyjnej CodePen, aby zobaczyć różnicę, jaką robi w różnych rozmiarach kontenerów.

Ponieważ naszym pierwotnym celem było umożliwienie spójnie responsywnych wymiarów obrazu , nadal osiągnęliśmy cel. Dla własnego przypadku użycia może być konieczne manipulowanie wartościami proporcji i wysokości, aby osiągnąć pożądany efekt.

Alternatywa: mix-blend-mode i dodawanie filtra

Użycie overlay jako wartości mix-blend-mode było najlepszym wyborem dla efektu zanikania do bieli, którego szukaliśmy, ale wypróbujmy alternatywną opcję, aby uzyskać bardziej dramatyczny efekt.

Zamierzamy zaktualizować nasze rozwiązanie, aby dodać niestandardową właściwość CSS dla wartości mix-blend-mode , a także zaktualizować wartości kolorów dla gradientu:

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

Wartość multiply ma wpływ na przyciemnienie tonów średnich, ale zachowuje biel i czerń bez zmian, co daje następujący wygląd:

Każdy obraz karty ma mocny pomarańczowy odcień z nowego gradientu, który zaczyna się od czerwono-pomarańczowego do czysto pomarańczowego. Białe obszary są nadal białe, a czarne obszary są nadal czarne
Każdy obraz karty ma mocny pomarańczowy odcień z nowego gradientu, który zaczyna się od czerwono-pomarańczowego do czysto pomarańczowego. Białe obszary są nadal białe, a czarne nadal są czarne. (duży podgląd)

Chociaż utraciliśmy zanikanie i teraz mamy twardą krawędź na dole obrazu, biała część naszego gradientu jest nadal ważna, aby zapewnić, że gradient kończy się przed zawartością karty.

Dodatkową modyfikacją , którą możemy dodać, jest użycie filter , aw szczególności użycie funkcji grayscale() , aby usunąć kolory obrazu, a zatem gradient będzie jedynym źródłem kolorowania obrazu.

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

Użycie wartości grayscale(100) powoduje całkowite usunięcie naturalnych kolorów obrazu i przekształcenie go w czerń i biel. Oto aktualizacja do porównania z poprzednim zrzutem ekranu z jej efektem podczas korzystania z naszego pomarańczowego gradientu z multiply :

Teraz każdy obraz karty nadal ma pomarańczowy gradient, ale wszystkie inne kolory są usuwane i zastępowane odcieniami szarości
Teraz każdy obraz karty nadal ma pomarańczowy gradient, ale wszystkie inne kolory są usuwane i zastępowane odcieniami szarości. (duży podgląd)

Użyj aspect-ratio jako progresywnego ulepszenia

Jak wcześniej wspomniano, obecnie aspect-ratio są obsługiwane tylko w najnowszych wersjach przeglądarek Chromium (Chrome i Edge). Jednak wszystkie przeglądarki obsługują object-fit a to wraz z naszymi ograniczeniami height daje mniej idealny, ale nadal akceptowalny wynik, jak tutaj dla Safari:

Wysokość obrazu karty jest ograniczona, ale każda karta ma nieco inną zrealizowaną wysokość
Wysokość obrazu karty jest ograniczona, ale każda karta ma nieco inną realizowaną wysokość. (duży podgląd)

Bez funkcji aspect-ratio rezultatem jest to, że ostatecznie wysokość obrazu jest ograniczona, ale naturalne wymiary każdego obrazu nadal prowadzą do pewnych różnic między wysokościami obrazu karty. Zamiast tego możesz chcieć dodać max-height lub ponownie skorzystać z funkcji max() , aby zwiększyć responsywność max-height na kartach o różnych rozmiarach.

Rozszerzenie efektów gradientu

Ponieważ zdefiniowaliśmy stopnie koloru gradientu jako niestandardową właściwość CSS, mamy łatwy dostęp do ich zmiany w różnych kontekstach. Na przykład możemy zmienić gradient, aby mocniej odzwierciedlał jeden z kolorów, jeśli na karcie znajduje się kursor lub jeden z jej elementów podrzędnych jest w centrum uwagi.

Najpierw zaktualizujemy każdą kartę h3 , aby zawierała link, taki jak:

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

Następnie możemy użyć jednego z naszych najnowszych dostępnych selektorów — :focus-within — do zmiany gradientu karty, gdy łącze jest aktywne. Aby uzyskać dodatkowe informacje o możliwych interakcjach, połączymy to z :hover . I ponownie użyjemy naszego pomysłu max() , aby przypisać pojedynczy kolor, który przejmie pokrycie części obrazu karty. Minusem tego konkretnego efektu jest to, że nie da się niezawodnie animować zatrzymywania gradientu i zmian kolorów — ale wkrótce będzie to możliwe dzięki CSS Houdini.

Aby zaktualizować kolor i dodać nowy znacznik koloru, wystarczy ponownie przypisać wartość --card-gradient w ramach tej nowej reguły:

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

Nasze wartości max() są mniejsze niż oryginalne używane dla white , aby zachować wtapianą krawędź. Gdybyśmy użyli tych samych wartości, zetknęłaby się z white i stworzyłaby wyraźną separację prostoliniową.

Tworząc to demo, początkowo wypróbowałem efekt, który wykorzystywał transform ze scale aby uzyskać efekt powiększenia. Odkryłem jednak, że z powodu zastosowania mix-blend-mode , przeglądarka nie będzie konsekwentnie odświeżać obrazu, co powodowało nieprzyjemne migotanie. Zawsze będą kompromisy w żądaniu, aby przeglądarka wykonała tylko efekty i animacje CSS, i chociaż jest to bardzo fajne, co możemy zrobić, zawsze najlepiej jest sprawdzić wpływ efektów na wydajność .

Baw się dobrze, eksperymentując!

Współczesny CSS dał nam kilka niesamowitych narzędzi do aktualizowania naszych zestawów narzędzi do projektowania stron internetowych, a najnowszym dodatkiem jest aspect-ratio . Więc idź dalej i poeksperymentuj z object-fit , aspect-ratio i dodawaniem funkcji takich jak max() do swoich gradientów, aby uzyskać zabawne, responsywne efekty! Tylko pamiętaj, aby dokładnie sprawdzić wszystko w różnych przeglądarkach (na razie!) oraz w różnych rzutniach i rozmiarach kontenerów.

Oto CodePen zawierający funkcje i efekty, które sprawdziliśmy dzisiaj:

Zobacz pióro [Efekty responsywnego obrazu z gradientami CSS i współczynnikiem proporcji](https://codepen.io/smashingmag/pen/WNoERXo) autorstwa Stephanie Eckles.

Zobacz Efekty graficzne reagujące na pióro z gradientami CSS i współczynnikiem proporcji autorstwa Stephanie Eckles.

Szukasz więcej? Koniecznie zajrzyj do naszego Przewodnika CSS tutaj na Smashing →