CSS躬行記(7)——合成
在圖形編輯軟件中,可以按特定地方式處理不同圖層的合成,最新的CSS規範也引入了該功能,並提供了mix-blend-mode和background-blend-mode兩個屬性。混合模式(blending mode)是一種數學算法,可計算元素重疊部分的顏色值,目前已定義了十多種不同的混合模式。
一、元素混合
元素混合是指將元素和其背後內容(backdrop,也叫背着物)混合,由mix-blend-mode屬性設置混合模式。元素背後既可以是另一個元素,也可以是父元素的背景,並且聲明了mix-blend-mode屬性的元素被稱為前景。注意,不同層疊上下文中的元素不能混合。接下來會對已有的混合模式逐個講解,並給出相應的計算公式,下面列出的是會用到的符號含義。
(1)Cr:計算後的顏色值。
(2)B:進行混合的公式。
(3)Cs:前景中的顏色。
(4)Cb:元素背後的顏色(backdrop color)。
1)darken
比較Cb和Cs的顏色分量(即R、G和B),選擇較暗的顏色,即保留較小值。
B(Cb, Cs) = min(Cb, Cs)
下面將img元素的mix-blend-mode屬性定義為darken,父元素div聲明了漸變背景。在下圖中,左側是img和div默認的混合效果,右側是使用了darken混合後的效果。
<style> div { background: linear-gradient(to right, rgb(48,129,242) 10%, rgb(255,204,0) 66%, rgb(255,102,0)); } img { mix-blend-mode: darken; } </style> <div> <img src="./avatar.png" /> </div>
2)lighten
與darken類似,但選擇較亮的顏色,即保留較大值,效果如下圖所示。
B(Cb, Cs) = max(Cb, Cs)
3)difference
取Cb和Cs顏色分量之差的絕對值,用較淺的顏色減去較深的顏色,效果如下圖所示。
B(Cb, Cs) = | Cb - Cs |
4)exclusion
與difference類似,但對比度更低,顏色更柔和,效果如下圖所示。
B(Cb, Cs) = Cb + Cs - 2 x Cb x Cs
5)multiply
將Cb和Cs中的顏色分量相乘,得到較暗的顏色,效果如下圖所示。
B(Cb, Cs) = Cb x Cs
6)screen
將Cb和Cs的顏色反轉,然後相乘,最後再反轉,效果如下圖所示。
B(Cb, Cs) = 1 - [(1 - Cb) x (1 - Cs)]
7)overlay
當Cb的顏色比Cs的顏色深時,執行multiply渲染;當Cb的顏色比Cs的顏色淺時,執行screen渲染,效果如下圖所示。
B(Cb, Cs) = HardLight(Cs, Cb)
8)hard-light
也是對multiply和screen的綜合應用,但判斷條件與overlay相反,效果如下圖所示。
if(Cs <= 0.5) B(Cb, Cs) = Multiply(Cb, 2 x Cs) else B(Cb, Cs) = Screen(Cb, 2 x Cs -1)
9)soft-light
與hard-light類似,但顏色更加柔和,效果如下圖所示。
if(Cs <= 0.5) B(Cb, Cs) = Cb - (1 - 2 x Cs) x Cb x (1 - Cb) else B(Cb, Cs) = Cb + (2 x Cs - 1) x (D(Cb) - Cb) with if(Cb <= 0.25) D(Cb) = ((16 * Cb - 12) x Cb + 4) x Cb else D(Cb) = sqrt(Cb)
10)color-dodge
不改變顏色,但會將其調亮,效果如下圖所示。
if(Cb == 0) B(Cb, Cs) = 0 else if(Cs == 1) B(Cb, Cs) = 1 else B(Cb, Cs) = min(1, Cb / (1 - Cs))
11)color-burn
與color-dodge的作用相反,將顏色調暗,效果如下圖所示。
if(Cb == 1) B(Cb, Cs) = 1 else if(Cs == 0) B(Cb, Cs) = 0 else B(Cb, Cs) = 1 - min(1, (1 - Cb) / Cs)
接下來的四個混合模式不操作顏色分量,而是以不同的方式合併Cs和Cb的色相、飽和度、亮度和顏色,會用到幾個輔助函數,如下所示。
Lum(C) = 0.3 x Cred + 0.59 x Cgreen + 0.11 x Cblue ClipColor(C) L = Lum(C) n = min(Cred, Cgreen, Cblue) x = max(Cred, Cgreen, Cblue) if(n < 0) C = L + (((C - L) * L) / (L - n)) if(x > 1) C = L + (((C - L) * (1 - L)) / (x - L)) return C SetLum(C, l) d = l - Lum(C) Cred = Cred + d Cgreen = Cgreen + d Cblue = Cblue + d return ClipColor(C) Sat(C) = max(Cred, Cgreen, Cblue) - min(Cred, Cgreen, Cblue) SetSat(C, s) if(Cmax > Cmin) Cmid = (((Cmid - Cmin) x s) / (Cmax - Cmin)) Cmax = s else Cmid = Cmax = 0 Cmin = 0 return C;
12)hue
將Cb的顏色的飽和度與亮度跟Cs中對應位置的色相合併,效果如下圖所示。
B(Cb, Cs) = SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb))
13)saturation
將Cb的顏色的色相與亮度跟Cs中對應位置的飽和度合併,效果如下圖所示。
B(Cb, Cs) = SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb))
14)color
將Cb的顏色的亮度跟Cs中對應位置的色相與飽和度合併,效果如下圖所示。
B(Cb, Cs) = SetLum(Cs, Lum(Cb))
15)luminosity
將Cb的顏色的色相與飽和度跟Cs中對應位置的亮度合併,效果如下圖所示。
B(Cb, Cs) = SetLum(Cb, Lum(Cs))
二、背景混合
背景混合適合一個元素包含多個背景的情況,由background-blend-mode屬性設置混合模式。當混合多個背景時,會從後往前進行混合。如果包含背景色,那麼首先由背景色與最下層的背景圖混合,其結果再與次下層的背景圖混合,以此類推。
在下面的示例中,包含兩個div元素,都使用lighten混合,其中第二個div元素包含背景色。兩個元素的混合效果如下圖所示,左側無背景色,右側有背景色。
<style> div { background: url(./avatar.png) no-repeat center, url(./lake.png); background-size: 40% 40%, cover; background-blend-mode: lighten; } .color { background-color: #F60; } </style> <div></div> <div class="color"></div>
注意,background-blend-mode屬性可接收多種混合模式,用逗號分隔,樣式如下,效果如下圖所示。
div { background-blend-mode: lighten, hard-light; }
三、隔離
在合成的過程中,還可通過isolation屬性隔離混合,即讓那些元素自成一組。注意,isolation屬性需要聲明到某個容器元素中,並且不能和混合模式存在於同一個元素上。
接下來用一個簡單的例子來演示isolation屬性的用法,首先創建HTML結構,section是img的祖先元素,div是img的父元素。
<section> <div> <img src="./avatar.png" class="blend" /> </div> </section> <section> <div class="isolation"> <img src="./avatar.png" class="blend" /> </div> </section>
然後添加CSS樣式,將混合模式聲明在img元素上,第二個div元素定義了isolation屬性。得到的效果如下圖所示,左側的祖先元素的背景會與圖像混合,而右側因為發生了隔離,所以就不會與背景混合。
section { background: linear-gradient(to right, #3081F2 10%, #FC0 66%, #F60); } .blend { mix-blend-mode: lighten; } .isolation { isolation: isolate; }
注意,建立層疊上下文的元素可自動獨立,而不受isolation屬性的影響,能發生層疊上下文的情形包括:
(1)文檔根元素,例如html元素。
(2)相對或絕對定位且z-index屬性值不為auto的元素。
(3)固定或粘滯定位的元素。
(4)彈性盒的子元素,且z-index屬性值不為auto。
(5)網格容器的子元素,且z-index屬性值不為auto。
(6)opacity屬性值小於1的元素。
(7)mix-blend-mode屬性值不為normal的元素。
(8)transform、filter、perspective、clip-path、mask、mask-image和mask-border屬性值不為none的元素。
(9)isolation屬性值為isolate的元素。
(10)-webkit-overflow-scrolling屬性值為touch的元素。
(11)contain屬性值為layout、paint或包含它們其中之一的合成值(例如strict、content)的元素。
(12)為will-change定義任一屬性。