CSS 顏色混合的 N 種方式
在項目中經常會碰到需要鄰近色的場景,比如將一個顏色變深(淺)一點,下面是一個按鈕的選中態
如果出現一種顏色就定義一個變量,每次都要維護多個顏色變量太麻煩了。有沒有辦法只用一個顏色呢?在這裏也就是,如何將一個顏色變淺一點?這樣做的好處是,如果需要更換主題色,只用修改一個變量就行了,如下
下面盤點我用過的一些方法
一、透明度
這應該是最容易想到的方式。將一個元素透明度降低不就顏色變淺了嗎?
假設 HTML
是這樣的(下同)
<button style="--primary-color: #3981E6">#3981E6</button>
不過這種方式需要藉助單獨一層標籤,通常可以用僞元素生成,關鍵實現如下
button::before{
content: '';
background: var(--primary-color);
opacity: 0.2
}
效果還是非常不錯的,下面是多種主題色的效果
不過這種方式也有侷限,比如僞元素不夠用怎麼辦?還有絕對定位引起的層級問題
沒關係,還有其他方式,接着往下看
二、多重背景
大家可能都知道,CSS3 背景是支持多重背景的,並且層級是越來越低的
因此,我們可以在主題色上覆蓋一層半透明的白色,依然可以將原有顏色 “減淡”
由於這裏是背景圖,所以需要用到漸變,而不是顏色。比如希望主題色減淡到自身的20%
,可以覆蓋80%
透明度的白色,實現如下
button{
background: linear-gradient(rgba(255,255,255,.8),rgba(255,255,255,.8)), /*半透明白色*/
linear-gradient(var(--primary-color), var(--primary-color));
}
這樣就無需藉助額外的標籤或者僞元素了,效果如下
不過這種方式也有一些缺陷,比如僅適合背景層,如果希望box-shadow
、outline
這些就不行,這些屬性沒法疊加多層背景。
三、動畫
這個方式在之前這篇文章中有詳細介紹:
主要原理是動畫播放次數也是支持小數的,比如設置一個從藍色到白色的動畫,播放次數爲0.8
,那麼在播放到80%
的地方就停下來了,這樣就得到了顏色減淡的效果,示意如下
具體實現如下
button{
animation: lighterBackgroundColor .001s 0.8 linear forwards;
/*播放次數爲0.8*/
}
@keyframes lighterBackgroundColor {
from {
background-color: var(--primary-color)
}
to{
background-color: #fff
}
}
效果也很棒
相比前一種方式,就沒有背景的限制了,任意屬性都可以,但是每出現一個屬性就需要單獨一個動畫(因爲動畫變化的就是屬性本身),如果要加一個減淡後的outline-color
,應該要這麼實現
button{
animation: lighterBackgroundColor .001s 0.8 linear forwards,
lighterOutlineColor .001s 0.8 linear forwards; /*outline*/
/*播放次數爲0.8*/
}
@keyframes lighterBackgroundColor {
from {
background-color: var(--primary-color)
}
to{
background-color: #fff
}
}
/*設置一個outline的動畫*/
@keyframes lighterOutlineColor {
from {
outline-color: var(--primary-color)
}
to{
outline-color: #fff
}
}
太繁瑣了,有沒有簡單一點的方法呢?
四、自定義屬性動畫
上面將屬性作爲動畫有點浪費,因爲變化值都是一樣的,有沒有辦法複用呢?
當然可以,將 CSS 變量作爲動畫對象,比如--lighterColor
button{
animation: lighterColor .001s 0.8 linear forwards;
/*播放次數爲0.8*/
}
@keyframes lighterColor {
from {
--lighterColor: var(--primary-color)
}
to{
--lighterColor: #fff
}
}
但是,僅僅這樣是不夠的,動畫並不認識這樣的變量,根本不會有動畫(就像display
一樣)
爲了讓自定義變量也支持動畫,需要通過@property
定義一下
@property - CSS:層疊樣式表 | MDN (mozilla.org)[1]
@property --lighterColor {
syntax: '<color>';
inherits: false;
initial-value: #fff;
}
相比前面的方式,但是適用性更佳,--lighterColor
已經是一個獨立的變量了,可以用在任意屬性上,比如加個outline
button{
background-color: var(--lighterColor);
outline: 4px solid var(--lighterColor);
}
可以看到,outline
也輕易地實現了顏色減淡
缺點就是,兼容性欠佳,目前firefox
還不支持
五、color-mix()
最後介紹一個最近正式支持(Chrome 110+)的顏色混合函數:color-mix()[2]
這個算是官方的解決方案了,如果這個普遍支持了,前面的方法都可以不用了,下面簡單介紹一下
color-mix(in lch, peru 40%, lightgoldenrod);
color-mix(in srgb, #34c9eb 20%, white);
前面的in lch
表示色彩空間,我們一般只用srgb
就足夠了,後面的兩個顏色就需要混合的顏色了。
這裏的百分比就是混合比例了,如果我們要實現減淡80%
的操作,可以將主題色的比例設置爲20%
,白色會自動填充剩餘比例,如下
button{
--lighterColor: color-mix(in srgb, var(--primary-color) 20%, #fff);
background-color: var(--lighterColor);
outline: 4px solid var(--lighterColor);
}
效果如下(Chrome 110+)
目前還不適合使用,過兩年再說吧🙁
下面是所有方案的效果對比,基本是一致的
完整 demo 可以訪問以下任意鏈接
-
CSS color lighter (juejin.cn)[3]
-
CSS color lighter (codepen.io)[4]
-
CSS color lighter (runjs.work)[5]
六、總結一下優缺點
以上共介紹了 5 種不同的顏色混合實現方式,各有優缺點,下面分別從以下幾個方面比較一下
-
實現成本:實現思路的複雜度,是否容易想到
-
適應性:能否適應各種場景
-
代碼複用性:實現是否囉嗦,是否需要額外標籤
-
兼容性:能否大規模使用
總的來說,自定義屬性動畫在各方面是比較推薦的,如果不考慮firefox
的話基本可以放心使用了,其他方式也可以根據實際需求自行選擇,哪個方便用哪個。
參考資料
[1] @property - CSS:層疊樣式表 | MDN (mozilla.org): https://developer.mozilla.org/zh-CN/docs/Web/CSS/@property
[2] color-mix(): https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color-mix
[3] CSS color lighter (juejin.cn): https://code.juejin.cn/pen/7206605166953365563
[4] CSS color lighter (codepen.io): https://codepen.io/xboxyan/pen/dyqRyVG
[5] CSS color lighter (runjs.work): https://runjs.work/projects/91dcf9cdd9f7447b
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/BoT-mgHhAhuhrnkV90TXug