毛玻璃效果是指用一層半透明的色片覆蓋複雜的背景,讓在毛玻璃前面的文字能容易閱讀。會這麼做是因為在背景裡有些有趣的地方,我們希望保留給使用者看得見,同時也要讓在前面的文字容易閱讀。
<main>
<blockquote>
"Sometimes I think I have felt everything I'm ever gonna feel. And from here on out, I'm not gonna feel anything new. Just lesser versions of what I've already felt."
<footer>-
<cite>
Theodore, Her (2013)
</cite>
</footer>
</blockquote>
</main>
body {
background: url(http://drive.google.com/uc?export=view&id=1ycTKvTds3B6SLQc44VqFAVp6ZY998P3E) 0 / cover fixed;
}
main {
background: hsla(0,0%,100%,.3);
}
(簡單的毛玻璃效果,文字看不太清楚)
但遇到極為複雜的背景時,簡單的毛玻璃無法突顯文字,如果我們減少毛玻璃層的透明度(提高alpha值,等同於減少透光度),雖然文字看清楚了,但也擋住了背景,讓畫面看起來少了趣味。
main {
background: hsla(0,0%,100%,.8);
}
(增加了背景的不透明度,同時也擋住了背景圖片)
在平面印刷設計上的解法是只把文字區塊的背景做模糊效果,模糊後的背景比較不複雜,讓文字容易閱讀。不過因為模糊化是個很耗運算資源的效果,以往在網頁和UI設計是被禁止的。然而近年來因為GPU和硬體加速愈來愈普及,模糊化後的毛玻璃效果也愈常見到。過去幾年我們能在微軟Windows以及蘋果的iOS和macOS看到毛玻璃效果被用在作業系統的介面。
我們也得到在CSS裡對元素進行模糊的能力,透過blur()
filter,CSS也有了SVG一向擁有的功能。然而如果我們直接對我們範例中的文字區塊用blur()
的話,整個元素都被模糊化了,根本就不知道文字在寫什麼。有沒有什麼方法可以只模糊文字區塊的背景呢?
main {
background: hsla(0,0%,100%,.3);
filter: blur(3px);
}
(用了blur()
後更糟)
我們的解決方法靈感來自前面提到的平面印刷,但是blur()
又不能用在文字區塊上,所以我們用文字區塊的偽元素做一個一模一樣大小的背景圖,blur()
就用在這個偽元素上所以不會影響到文字,然後再將它移到文字區塊後面。
首先做一個偽元素,然後用absolute定位,讓它蓋過整個文字區塊(也就是<main>
)。
main {
position: relative;
/* 其他的樣式 */
}
main::before {
content: '';
position: absolute;
top:0; right:0; bottom:0; left:0;
background: rgba(255,0,0,.5); /* debug用的紅色背景 */
}
(紅色的偽元素擋在內容前面)
我們把要模糊化的偽元素背景先用紅色背景色代替,這樣比較好理解,不然透明的背景我們什麼也看不到,出錯了根本不知道錯在哪裡。
這時明顯的看到,偽元素背景現在是覆蓋在內容之上,所以我們用z-index: -1
把它移到後面去。
現在是時候將紅色換成我們的背景圖,然後加上模糊效果。
看起來不賴,文字區塊中心的模糊效果很好,但是愈接近邊緣模糊的程度就不是那麼強。對blur radius原理「高斯模糊」可以看這裡的解釋,簡單來說這個「模糊半徑」愈長,圖片平滑的效果愈好,但因為高斯模糊是以常態分佈來分配權重,於是愈靠近中心的像素權重愈高,模糊效果愈強,反之愈遠離則愈弱。如果我們把前面清除的紅色背景加回來,就能清楚的發現效果強弱的分佈。
(從紅色背景可以看出模糊效果的強弱分佈)
為了讓毛玻璃有平均的模糊程度(你有看過透明度不一的毛玻璃嗎?),我們把偽元素尺寸加大,每邊至少margin: -20px
,和blur radius相等,避免不同瀏覽器對blur的演算法不同而破壞我們的畫面。這時可以看到模糊效果超出了文字區塊,在文字區塊加上overflow: hidden
就可以了。
body, main::before {
background: url(http://drive.google.com/uc?export=view&id=1ycTKvTds3B6SLQc44VqFAVp6ZY998P3E) 0 / cover fixed;
}
main {
background: hsla(0,0%,100%,.3);
position: relative;
overflow: hidden;
/* 其他樣式 */
}
main::before {
content: '';
position: absolute;
top:0; right:0; bottom:0; left:0;
filter: blur(20px);
z-index: -1;
margin: -30px;
}
最後加上一些陰影和文字效果,毛玻璃就大功告成了。
CodePen
註:文章寫完才覺得最後的成果跟一開始增加alpha值的效果差不多,所以在CodePen裡把blur-radius減少到5px,因為我的文字區塊其實不大,原本照書中設的20px值太大了。不過圖也貼了,就懶得改,等以後修訂時再來訂正吧。