使用 CSS 漸變和縱橫比創建響應式圖像效果
已發表: 2022-03-10aspect-ratio
屬性與object-fit
相結合,為過去令人頭疼的問題提供了一種補救措施! 讓我們學習使用這些屬性,以及創建響應式漸變圖像效果以獲得額外的天賦。為了準備我們未來的圖像效果,我們將設置一個卡片組件,頂部有一個大圖像,後面是標題和描述。 這種設置的常見問題是我們可能並不總是完美地控製圖像是什麼,更重要的是我們的佈局,它的尺寸是什麼。 雖然這可以通過提前裁剪來解決,但由於容器大小的響應,我們仍然會遇到問題。 結果是卡片內容的位置不均勻,當你出示一排卡片時,它真的很突出。
除了裁剪之外,另一個先前的解決方案可能是從內聯img
交換到一個空白div
,該 div 僅存在於通過background-image
呈現圖像。 過去我自己多次實施過這個解決方案。 這樣做的一個優點是使用一種較舊的縱橫比技巧,該技巧使用零高度元素並設置padding-bottom
值。 將填充值設置為百分比會產生相對於元素寬度的最終計算值。 您可能還使用這個想法來保持視頻嵌入的 16:9 比例,在這種情況下,填充值可以通過以下公式找到: 9/16 = 0.5625 * 100% = 56.26%
。 但是我們將探索兩個不涉及額外數學的現代 CSS 屬性,給我們更多的靈活性,並且還允許通過使用真實的img
而不是空的div
來保持語義。
首先,讓我們定義 HTML 語義,包括使用無序列表作為卡片的容器:
<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>
接下來,我們將為.card
組件創建一組最小的基線樣式。 我們將為卡片本身設置一些基本的視覺樣式,快速更新預期的h3
標題,然後開始設置卡片圖像樣式的基本樣式。
.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; }
最後一條規則使用通用兄弟組合器為img
之後的任何元素添加水平邊距,因為我們希望圖像本身與卡片的側面齊平。
到目前為止,我們的進展導致我們出現以下卡片外觀:
最後,我們將使用 CSS 網格創建快速響應佈局的.card-wrapper
樣式。 這也將刪除默認列表樣式。
.card-wrapper { list-style: none; padding: 0; margin: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(30ch, 1fr)); grid-gap: 1.5rem; }
注意:如果您不熟悉這種網格技術,請查看我的教程中關於 12 列網格的現代解決方案的說明。
應用了這個並且所有卡片都包含具有有效源路徑的圖像,我們的.card-wrapper
樣式為我們提供了以下佈局:
如預覽圖像所示,這些基線樣式不足以正確包含圖像,因為它們具有不同的自然尺寸。 我們需要一種方法來統一和一致地約束這些圖像。
啟用具有object-fit
統一圖像大小
如前所述,您之前可能已在此場景中進行了更新,以更改要通過background-image
添加的圖像,並使用background-size: cover
來很好地調整圖像大小。 或者您可能已經嘗試提前強制裁剪(這仍然是一個有價值的目標,因為任何圖像尺寸減小都會提高性能!)。
現在,我們有了object-fit
屬性,它可以讓img
標籤充當圖像的容器。 並且,它還帶有一個cover
值,可以產生與背景圖像解決方案類似的效果,但具有保留內聯圖像語義的好處。 讓我們應用它,看看它是如何工作的。
我們確實需要將它與height
尺寸配對,以獲得關於我們希望圖像容器如何表現的額外指導(回想一下我們已經添加了width: 100%
)。 我們將使用max()
函數來選擇10rem
或30vh
,具體取決於給定上下文中哪個更大,這可以防止圖像高度在較小的視口或用戶設置大縮放時縮小太多。
img { /* ...existing styles */ object-fit: cover; height: max(10rem, 30vh); }
額外的輔助功能提示:您應該始終在桌面上使用 200% 和 400% 縮放來測試您的佈局。 雖然目前沒有zoom
媒體查詢,但max()
等函數可以幫助解決佈局問題。 該技術有用的另一個上下文是元素之間的間距。
通過這次更新,我們確實改進了一些東西,視覺效果就好像我們使用了舊的背景圖像技術:
響應一致的圖像大小與aspect-ratio
當單獨使用object-fit
時,一個缺點是我們仍然需要設置一些維度提示。
即將推出的屬性(目前在 Chromium 瀏覽器中可用)稱為aspect-ratio
,將增強我們一致地調整圖像大小的能力。
使用這個屬性,我們可以定義一個比率來調整圖像的大小,而不是設置明確的尺寸。 我們將繼續將它與object-fit
結合使用,以確保這些尺寸僅影響作為容器的圖像,否則,圖像可能會出現失真。
這是我們完整更新的圖像規則:
img { border-radius: 0.5rem 0.5rem 0 0; width: 100%; object-fit: cover; aspect-ratio: 4/3; }
對於卡片上下文,我們將從4 ⁄ 3的圖像比例開始,但您可以選擇任何比例。 例如, 1 ⁄ 1表示正方形,或16 ⁄ 9表示標準視頻嵌入。
這是更新後的卡片,儘管在這個特定實例中可能很難注意到視覺差異,因為縱橫比恰好與我們通過單獨設置object-fit
height
獲得的外觀非常匹配。
設置 `aspect-ratio` 會導致比例隨著元素的增長或縮小而保持不變,而當僅設置 `object-fit` 和 `height` 時,圖像比例將隨著容器尺寸的變化而不斷變化。
“
使用 CSS 漸變和函數添加響應式效果
好的,現在我們知道瞭如何設置一致大小的圖像,讓我們通過添加漸變效果來享受它們的樂趣!
我們使用此效果的目標是讓它看起來好像圖像正在淡入卡片內容。 您可能很想將圖像包裝在自己的容器中以添加漸變,但是由於我們已經在圖像大小方面所做的工作,我們可以弄清楚如何在主.card
上安全地執行此操作。
第一步是定義梯度。 我們將使用 CSS 自定義屬性添加漸變顏色,以便輕鬆交換漸變效果,從藍色到粉紅色開始。 漸變中的最後一種顏色將始終為白色,以保持過渡到卡片內容背景並創建“羽化”邊緣。
.card { --card-gradient: #5E9AD9, #E271AD; background-image: linear-gradient( var(--card-gradient), white max(9.5rem, 27vh) ); /* ...existing styles */ }
但是等等——這是一個 CSS max()
函數嗎? 在漸變中? 是的,這是可能的,而且它是使這個漸變響應有效的魔力!
但是,如果我要添加屏幕截圖,我們實際上不會看到漸變對圖像有任何影響。 為此,我們需要引入mix-blend-mode
屬性,在這種情況下,我們將使用overlay
值:
img { /* ...existing styles */ mix-blend-mode: overlay; }
mix-blend-mode
屬性類似於應用 Photoshop 等照片處理軟件中可用的圖層混合樣式。 並且overlay
值將具有允許圖像中的中等色調與其後面的漸變混合的效果,從而導致以下結果:
現在,此時,我們僅依靠aspect-ratio
來調整圖像大小。 如果我們調整容器大小並導致卡片佈局重排,則不斷變化的圖像高度會導致漸變漸變為白色的位置不一致。
因此,我們還將添加一個max-height
屬性,該屬性也使用max()
函數並包含比漸變中的值稍大的值。 由此產生的行為是漸變將(幾乎總是)正確地與圖像底部對齊。
img { /* ...existing styles */ max-height: max(10rem, 30vh); }
需要注意的是,添加 `max-height` 會改變 `aspect-ratio` 行為。 它不會總是使用精確的比例,而是僅在給定“最大高度”的新額外約束時有足夠的分配空間時使用。
“
但是, aspect-ratio
仍將繼續確保圖像大小一致地調整,這與僅object-fit
相比具有優勢。 嘗試在最終的 CodePen 演示中註釋掉aspect-ratio
,以查看它在不同容器大小之間的差異。
由於我們最初的目標是實現一致的響應式圖像尺寸,因此我們仍然達到了目標。 對於您自己的用例,您可能需要調整比率和高度值以達到您想要的效果。
替代方案: mix-blend-mode
並添加過濾器
使用overlay
作為mix-blend-mode
值是我們正在尋找的淡入白效果的最佳選擇,但讓我們嘗試另一種選擇以獲得更戲劇性的效果。
我們將更新我們的解決方案,為mix-blend-mode
值添加 CSS 自定義屬性,並更新漸變的顏色值:
.card { --card-gradient: tomato, orange; --card-blend-mode: multiply; } img { /* ...existing styles */ mix-blend-mode: var(--card-blend-mode); }
multiply
值對中間色調有暗化效果,但保持白色和黑色不變,從而產生以下外觀:
雖然我們已經失去了淡入淡出並且現在在圖像底部有一個硬邊,但我們漸變的白色部分仍然很重要,以確保漸變在卡片內容之前結束。
我們可以添加的另一個修改是使用filter
,特別是使用grayscale()
函數來去除圖像顏色,因此漸變是圖像著色的唯一來源。
img { /* ...existing styles */ filter: grayscale(100); }
使用grayscale(100)
的值會導致完全去除圖像的自然顏色並將其轉換為黑白。 這是與之前使用我們的橙色漸變和multiply
效果的屏幕截圖進行比較的更新:
使用aspect-ratio
增強
如前所述,目前僅最新版本的 Chromium 瀏覽器(Chrome 和 Edge)支持aspect-ratio
。 然而,所有的瀏覽器都支持object-fit
,再加上我們的height
限制,導致了一個不太理想但仍然可以接受的結果,在這裡可以看到 Safari:
如果沒有aspect-ratio
功能,這裡的結果是最終圖像高度被限制,但每個圖像的自然尺寸仍然導致卡片圖像高度之間的一些差異。 您可能希望改為添加max-height
或再次使用max()
函數來幫助使max-height
卡片尺寸下更具響應性。
擴展漸變效果
由於我們將漸變色標定義為 CSS 自定義屬性,因此我們可以隨時在不同的上下文中更改它們。 例如,如果卡片懸停或其中一個子元素處於焦點位置,我們可能會更改漸變以更強烈地顯示其中一種顏色。
首先,我們將更新每張卡片h3
以包含一個鏈接,例如:
<h3><a href="">A Super Wonderful Headline</a></h3>
然後,我們可以使用我們最新的可用選擇器之一 - :focus-within
- 在鏈接處於焦點時更改卡片漸變。 為了額外覆蓋可能的交互,我們將把它與:hover
結合起來。 而且,我們將重用我們的max()
想法來分配一種顏色來接管卡片圖像部分的覆蓋範圍。 這種特殊效果的缺點是漸變停止和顏色變化不能可靠地動畫化——但由於 CSS Houdini,它們很快就會實現。
要更新顏色並添加新的色標,我們只需要在這個新規則中重新分配--card-gradient
的值:
.card:focus-within, .card:hover { --card-gradient: #24a9d5 max(8.5rem, 20vh); }
我們的max()
值小於用於white
以保持羽化邊緣的原始值。 如果我們使用相同的值,它將遇到white
並創建一個清晰的直尺分離。
在創建這個演示時,我最初嘗試了一個使用帶有scale
的transform
來實現放大效果的效果。 但我發現,由於應用了mix-blend-mode
,瀏覽器不會始終如一地重新繪製圖像,從而導致令人不快的閃爍。 請求瀏覽器執行純 CSS 效果和動畫總是需要權衡取捨,雖然我們可以做的很酷,但最好檢查效果對性能的影響。
體驗愉快!
現代 CSS 為我們提供了一些很棒的工具來更新我們的網頁設計工具包,其中最新添加的aspect-ratio
。 因此,繼續嘗試object-fit
、 aspect-ratio
,並在漸變中添加諸如max()
之類的函數,以獲得一些有趣的響應效果! 請務必仔細檢查跨瀏覽器(現在!)以及不同的視口和容器大小。
這是 CodePen,包括我們今天回顧的功能和效果:
尋找更多? 確保您在 Smashing 上查看我們的 CSS 指南 →