前幾天把一份別人的 Photoshop 設計稿做成網站,發現裡面用了不少 PS 圖層混合模式,例如下圖兩個簡易 wireframe 範例

圖左有一組清單,標題跟內文各有背景色,清單上面有一些透明圖案,會跟標題和內文的背景色混合。
只是把圖存成 PNG 蓋在上面肯定是不可行的,因為要跟底下其他區域混合後,才會是正確的顏色。
也無法把圖案墊在最下面,會被標題跟內文的背景圖蓋住,當然顏色也會不對。
用 RWD 的思考邏輯,肯定無法把圖案切開直接做在那幾個標題跟內文裡面,因為螢幕寬度改變時,標題與內文可能會換行或變少一行,高度就不一樣了,還有螢幕比較小時,容器外間距跟圖形肯定不會留這麼大,圖形的大小位置都會改變。

圖右有幾顆圖片造型按鈕,上面蓋著一些不可以斷掉的造型圖形,
除了跟上面幾點差不多的問題,用 RWD 的思考邏輯,螢幕寬度不同時,按鈕文字可能會改變,按鈕左右內距可能會改變,按鈕之間的距離可能會加大或縮窄。

看來又要出動 CSS 的圖層混合模式了。

什麼是圖層混合模式?

圖層混合模式並不是 Photoshop 特有的東西,illustrator 和其他 Adobe 全家餐幾乎都有,基本上不管是市面上的商業軟體或開源軟體,稍微完整的數位影像工具(繪圖/影片/影像處理…)都會有這功能,這算是計算機圖學的東西,沒有誰抄誰的問題。
簡單來說就是每一種圖層混合模式都有一組數學公式,讓重疊區域的像素,透過一些 RGB 數值的加減乘除,得到不同的顯示效果。
更詳細的說明可以參考:

圖層混合模式的應用

純視覺設計做圖的應用,例如一些玻璃杯/水晶球與背景照合成、合成湖面倒影、陰影、火焰、煙霧、假去背的時候都會用到,有些設計人員可能會看過 ai 檔案裡有星芒圖案,但是把背景拿掉之後卻變成一團黑黑的漸層,都是用了圖層混合模式。

網頁上的應用也不少,自從 IE 瀏覽器死透了之後,我也已經用了好幾次,但都是用在一些神奇的用途,例如:
– 如本例,原稿設計時就使用圖層混合模式,而且 RWD 設計上無法直接整張平面化拿去用。
– 滑鼠移入或點擊時讓圖片有個效果,可以讓圖長得不一樣,但又不用額外多做一張圖,css filter 或 mask 也可以用。
– 類似假浮水印或改色調的用途,直接讓網頁裡的圖片顯示成另一個樣子,就不用全部重新做圖上傳。
– 網頁前景有個動態效果,用各種方法實作,最後是 mp4 檔案最小,想要拿掉影片的黑底或白底背景,讓網頁本身的背景圖片顯示出來。
video tag 放 webm 影片 Alpha transparency in Chrome video – Chrome Developers 看似可以達成需求,但是在 iOS Safari 有瀏覽器相容性問題無法正常顯示,最後用 mix-blend-mode 成功硬幹出來(僅適用於影片裡的主體有一個固定不動的形狀),不過這種需求應該也可以用瀏覽器支援性更差的 css mask。

蘋果官網在某一段時間開始也很常用,例如 iPhone 14 這個網頁第一段的文案,隨著捲動時整塊區域的文字有不同顏色的效果。

不過有些人都覺得這個只是把字擺上去,字這麼大,像是在做 PPT,壓根不覺得技術上有什麼特別的,只有一些經常看國外設計網站,還有可憐的基層人員才看出箇中趣味。

CSS 混合模式的問題 1 – 比 PS 少很多

回到開頭的問題,要把繪圖軟體裡用到的效果實作在網頁上,最大的一個問題
Photoshop CC 2023(v24) 的圖層混合模式選單裡面,不算「正常」的話,選項有 26 個
但是 css 的 mix-blend-mode 的屬性值,照 MDN docs 文件,排除 unset, initial, normal, inherit,PS 沒有的 plus-lighter, plus-darker, revert, revert-layer 也先不算,現階段總共只有 15 個。
兩邊數量根本對不起來,那要怎麼實作設計呢?

以下用 Photoshop 繁體與 CSS mix-blend-mode 的屬性值做個對照,簡體中文版名詞只列 CSS mix-blend-mode 有的

Photoshop 混合模式名稱簡中mix-blend-mode
穿過
溶解
變暗變暗darken
色彩增值正片疊底multiply
加深顏色顏色加深color-burn
線性加深
顏色變暗
變亮變亮lighten
濾色濾色screen
加亮顏色顏色減淡color-dodge
線性加亮(增加)
顏色變亮
覆蓋疊加overlay
柔光柔光soft-light
實光強光hard-light
強烈光源
線性光源
小光源
實色疊印混合
差異化差值difference
排除排除exclusion
減去
分割
色相色相hue
飽和度飽和度saturation
顏色顏色color
明度亮度luminosity

線性加深(linear burn)、顏色變暗(darker color)、線性加亮(增加)(linear dodge(add))、強烈光源(vivid light)、減去(subtract)、分割(divide)都是繪圖軟體有,但是 CSS 沒有的。

運行在網頁瀏覽器內的 UI 設計軟體 Figma,也只有提供那些 css 有的圖層混合選項。

不過從一些 N 年前的文章發現有人照那些圖層混合算法寫 js 產生 canvas,有興趣的人可以參考看看
PhotoShop图层混合模式的Canvas实现 有列出一些混合模式的公式算法
Image Blend modes and HTML Canvas 把開頭載入圖片的 error 修掉之後,還是無法如預期照公式算法產生想要的圖片
Adding color-dodge/divide blending mode in fabric.js 這個範例是單張圖與一個顏色做混合,跟本文需求不一樣,不過 fabric.js 版本也太舊了

CSS 混合模式的問題 2 – 各種瀏覽器相容性問題

還是那句,不出意外的話就要出意外了。

這邊放個簡單的 demo,主要就是把三張不透明的圓形圖片,透過圖層混合模式讓重疊的部分混色,各大類混合模式各挑了一個做代表,然後圓形圖片分別是 png, svg tag, svg 放在 img tag。

iOS 又跟別人顯示得不一樣,外容器要另外多加 isolation:isolate,才會跟別的瀏覽器顯示得一樣,以免又不知道混色混到哪裡去了。

然後在客人那邊的 Macbook 會出現類似破圖的情況,顯示出來的不是原圖沒混合的樣子,也不是任何一種圖層混合效果,完全變成一種全新的特效。在我這邊的 macOS 設備都無法重現,而且通常重新整理又會正常顯示,所以無法像發現新的星星一樣命名。
排查問題:
– 新舊款筆電機型都有機會,也跟瀏覽器版本啥的無關,就我自己碰不到。
– 問題圖片都是 png,所以應該跟 jpg 圖片轉存時選 Progressive 還是 Baseline 無關。
– 有多處使用 mix-blend-mode,但是剛好 mix-blend-mode: color-dodge 的出問題? 不知道是巧合還是 bug。
– 沒有用到其他會觸發 The stacking context 的屬性,code 本身應該沒問題。
– 圖片沒有做 css animation 或其他效果,所以跟 Chrome css3 mix blend mode bug in chrome 可能沒什麼關係。

結論

除了瀏覽器相容性問題,如果是像本次現實使用需求,會把圖蓋在可操作的 UI 元件上,記得要設 z-index 或 points-events,以免做出看得到但點不到的按鈕。

CSS 除了 mix-blend-mode,還有更加複雜的 background-blend-mode,就跟 background 屬性一樣可以設定多組值,常看到國外的神人拿 background-blend-mode 搭配 linear-gradient 拿來做出各種圖案的背景圖,讓人讚嘆數學好的人真的是可以為所欲為。

額外加戲:網路上的迷因圖

好色龍 – 雜七雜八短篇漫畫翻譯1842 看到一張有趣的圖,一張長得像 CMY 混色圖的加上一堆線,看起來就能讓人產生幻覺?

由於圖片上傳到社群網站會壓縮圖片,還有圖片會平滑化,圖片中白色的地方去吸顏色肯定不是純白的(#FFFFFF, rgb:255,255,255)。那些線段肯定也不是單一藍色或單一黑色,我另外做了個網頁來玩玩。

上面那個框框往下捲動可以看到兩個實驗範例:
實驗1:只是單純在青色和洋紅圈圈上面加上一堆藍色的線,就會讓人覺得右下角有一個黃色的圓?
如果把右下那個圓改成白色,會發現右下角什麼都沒有。
實驗2:只是單純畫一堆藍色和黑色的線條,就能讓人覺得中間有一個黃色的圓? 可以調整畫面上的藍色線段寬度試試。


原圖的奧秘應該在那些藍色線段,有一區塊是黑色的,應該是補色的關係。