如何通過 HTML5 實現 iOS 7 的實時毛玻璃模糊效果?

問了不少前輩,都說H5隻能事先通過視覺把毛玻璃效果做出來,然後進行替換,實際是個假的毛玻璃效果。並無法像原生應用及系統那樣對界面實現實時毛玻璃效果。
實際上或在未來是否有可能通過H5實現這類原生效果?

實時毛玻璃效果:即將底層內容模糊化(非靜態圖片)。


所謂的毛玻璃效果其實是半透明+模糊,可以用CSS filter實現。
時間不多,就拋個磚,題主可以自己找一下文檔和更多案例。
filter - CSS

div {
-moz-filter: blur(5px);
-webkit-filter: blur(5px);
-o-filter: blur(5px);
-ms-filter: blur(5px);
filter: blur(5px);
}

大體思路是,當出現彈出層的時候,對背景層增加blur filter,再給彈出層的一定透明度就可以了。

因為有同學堅持說 CSS filter 只能用於圖片,所以錄了一個小視頻,證明它是可以用於可視的DOM元素的。
視頻封面blur視頻
在 codepen 上找了一個栗子,是通過CSS filter + JS複製滾動元素實現的毛玻璃 Nav Bar 效果,也可以說明,這個屬性真的不是只能作用於圖片,也不需要「截屏」啊。iOS 7 Blurred Header


推薦這篇博客小tip: 使用CSS將圖片轉換成模糊(毛玻璃)效果 ? 張鑫旭介紹了三種方法。
分別是目前大多數人說的CSS3的filter,還有SVG的濾鏡,和用Canvas實現高斯模糊StackBlur。
我來補實際的效果圖吧,方法是按 @孟爽paula 來的,彈出的時候底層加模糊,彈出層加透明。
初始狀態:

modal彈出後:

ios6+沒問題,android得4.4。
所以更通用一點的得用Canvas來模擬,不過這個我還沒試。


先放代碼:

.navbar {

/* Safari for macOS iOS */
-webkit-backdrop-filter: blur(15px);

/* Google Chrome */
backdrop-filter: blur(15px);

/* 設置背景半透明黑色 */
background: rgba(0, 0, 0, 0.8);

}

macOS High Sierra Safari 運行效果如下(Safari for iOS 也是支持的,為了你的流量就不放圖啦~):

在 Chrome 62 里運行效果如下:

Ps:貌似 box-shadow 的區域也會被 Chrome 算在 backdrop-filter 的繪製區域里,因此會出現一些比較鬼畜的效果嗯泥萌自己去試試吧~(感謝評論區 @穆曉煒 的指出)。


原理:

運用了 CSS3 的 backdrop-filter 屬性,引用一下 MDN 的介紹:

The backdrop-filter property provides for effects like blurring or color shifting the area behind an element, which can then be seen through that element by adjusting the element"s transparency/opacity.

大意就是這個屬性可以對某個元素下層的東西添加濾鏡,不只是模糊,亮度對比度什麼的都可以辦到,原文:backdrop-filter


瀏覽器支持:

目前 CSS 里的 backdrop-filter 只支持桌面版和 iOS 版本的 Safari,且需要 -webkit- 前綴;桌面版 Chrome 倒是也支持,但是需要去 chrome://flags#enable-experimental-web-platform-features 里啟用實驗性網路平台功能

而且 Chrome 貌似對該濾鏡的支持效果不太好(其實就是盒子的範圍各種算不對…),Apple 官網在 Chrome 里打開都會有位移的現象出現,請看那個「購買」的按鈕:

具體的瀏覽器支持信息參見 Can I use... Support tables for HTML5, CSS3, etc

截至回答時情況如下(不太樂觀):


小改進:

/* 若瀏覽器支持 backdrop-filter,則透明度為 50%,並啟用毛玻璃 */
@supports (-webkit-backdrop-filter: blur(10px)) or (backdrop-filter: blur(10px)) {
.navbar {
background: rgba(0, 0, 0, 0.5);
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
color: #eee;
}
}

/* 若瀏覽器器不支持,則使用 MaterialDesign 的風格 */
@supports not ((-webkit-backdrop-filter: blur(10px)) or (backdrop-filter: blur(10px))) {
.navbar {
background: #fff;
color: #333;
box-shadow: 0px 10px 30px rgba(0, 0, 0, .18), 0px 6px 10px rgba(0, 0, 0, .22);
}
}

出來的效果是這個樣子的:


關於其他方法:

其他答者有說到 CSS Regions 的方發,其實是可以的,就是實在太折騰,而且 CSS Regions 也已經被 Google 放棄了。


一個小展望:

M$ 最近公布了自己的 Fluent Design 系統,裡邊也有大量的所謂的「毛玻璃」的存在,所以 Edge 支持 backdrop-filter 應該也不遠啦~

附一個投票鏈接,希望 Edge 快快支持的可以去投個票:Backdrop filters

FF 這邊倒是 Under Development,所以可以簡單地理解成 coming soon……?

考慮到毛玻璃主要運用在 Apple 家的生態里,使用 -webkit-backdrop-filter 來做其實是最無痛的辦法了,姑且把它當作一個 Safari 里打開網頁時的 bonus 吧,別太死摳這個細節就好,有則更好,沒有也成。


使用H5是可以實現iOS7風格毛玻璃效果的。但是不代表你可以隨意使用這種效果。這裡面需要一些前提條件。

從技術的角度分析這個事兒需要滿足幾個技術上的必備條件:
1、需要能將圖片模糊的濾鏡。
2、需要捕獲到毛玻璃浮層下面所有內容的圖像信息。就好像截屏。
3、需要讓圖片運動能與瀏覽器滾動同步。主要難點在於實時同步,尤其是處理滾動的慣性。

實現的思路就是對毛玻璃浮層之下的內容進行「捕屏」獲取圖片資源。然後以此圖片進行模糊處理並作為毛玻璃浮層的背景層。之後需要一些js代碼監視內容滾動,同步調整毛玻璃層背景圖的position使其能與內容滾動保持同步。

以目前瀏覽器對H5的支持,第一條可以通過CSS Filter實現。如 @winter所述。第二條也能實現,需要神奇的html2canvas。第三條比較麻煩,需要自己處理。要想做到跨瀏覽器跨設備支持難度不小。

整個效果做出來大概就是 @姚冬給的這個例子。瀏覽器方面IE 10+,目前的Chrome、Firefox、Safari都能跑出效果來。但是這個方案還不夠實戰價值,主要問題有:
1、你必須保證浮層下面的內容沒有Gif、Flash、視頻、滾動播放的文字圖片以及任何可能會動的東西。因為捕屏的開銷還是比較大的。尤其是有大量圖片資源的時候。
2、流暢度的問題。桌面瀏覽器中Chrome、IE、Firefox表現尚可。Safari因為設計上比別的瀏覽器有更多功耗方面的要求,所以必須強制開啟GPU加速後才能流暢。移動版需要使用最新的iPhone 5s、iPad Air才能有接近流暢的表現。更不用提有的Android版Chrome對於Blur濾鏡糟糕的表現效果。
3、同步滾動的問題。因為不同瀏覽器對於滾動的處理有所不同。尤其是滾動慣性的問題。例如在iOS上觸摸滾動內容時當觸摸事件停止後內容繼續按原方向慣性運動一段時間。但是這時候的滾動浮層不一定能捕獲到。 @姚冬給的例子就有這個問題。

最後:個人認為如果是想做for iOS 7的web app,那完全不必糾結毛玻璃這個效果。一方面這方面的投入對用戶體驗影響不大。另一方面隨著iOS 7.1的推出iOS自身應用這個效果的場景也在淡化對半透明模糊的強調。所以大可不必為此投入太多精力。誰知道iOS 8又會是什麼新樣子呢。
========================================================================
Update 1
---------------------------------------------------------------------------------------------------------------
收到了 @孟爽paula的評論,提到不用「捕屏」也可以實現。

首先,我不是說css filter必須作用於圖片。在這裡鄭重聲明,本人絕無此意!!!

看了提供的例子。確實沒有用捕屏。但是我認為這個例子在實際使用過程中可能會遇到一些問題。我個人不是特別傾向這種做法。
根據iOS 7 Blurred Header的源碼,這裡使用的方案是拷貝dom節點到浮層內然後對浮層進行blur。對於相對簡單的內容確實很有效。但是如果被複制dom節點內帶有使用id屬性唯一標記的元素,以及被複制節點內包含了一些隨js執行其狀態不可預測的元素。又或者頁面樣式的css選擇器依賴某種外層的容器。那就可能導致所複製的內容與原始內容渲染出來的效果不一致。
簡單的來說我個人認為這個方案通用性要略遜一些。

剛才看了 @劉小樂提供的CSS Regions解決方案,感覺這才是終極解決方案。可惜瀏覽器支持還需要等兩年。


-webkit-backdrop-filter:blur(15px);
background:rgba(255,255,255,0.4);

不謝。backdrop-filter:blur會將上層部分模糊,用法類似filter:xxx!backdrop-filter只支持IOS9.1+,詳情:Can I use... Support tables for HTML5, CSS3, etc,

另詳解:高級CSS filters_filter, backdrop-filter, filter() 教程_w3cplus


我想知道。支持CSS3的IE11 IE10反而不支持這種特效了。ie7-9還能支持。我已測試了很久。谷歌,火狐,ie7-9都能實現。實現的效果好壞,先不談。至少IMG肯定都能搞定。只有IE10-11就是兩個奇葩。filter:blur,svg引用,filter: progid:DXImageTransform.Microsoft.Blur全都沒效果。


補充一個 Canvas 的方案:使用 Canvas 繪製網頁快照,然後進行高斯模糊處理可以實現 Blur with Canvas
模糊掉的 B站(圖片似乎不會被繪入 canvas):

參考:

  1. html2canvas
  2. Using HTML5/Canvas/Javascript to take screenshots
  3. StackBlur

要做到類似iOS7的毛玻璃遮罩效果,單純css3 filter還不夠,還需要用到CSS Regions定義內容流。CSS Regions允許開發者定義位置容器,然後指定實際的內容元素在一個或多個位置容器間流動,這就給毛玻璃遮罩提供了可能。

例如:要實現iOS7頂部和底部毛玻璃遮罩,具體思路可以是這樣:
定義3個位置容器,分別對應頂部區域、中間區域、底部區域,在頂部和底部應用filter:blur。指定實際的頁面內容元素依次"流入"這3個位置容器。

比起截屏+模糊處理,使用CSS Regions方案更加底層和高效。缺點是還處於試驗階段,優點是高效。

CSS Regions目前還處於實驗階段,chrome下打開chrome://flags/#enable-experimental-web-platform-features, 開啟實驗特性即可。

就目前,使用內容拷貝+同步滾動的方式模擬內容流不失為一種解決方案,參見 孟爽paula 的答案。

CSS Regions+filter實現毛玻璃 參見:Blurry Transparent Header Effect from iOS7 in CSS


哈哈,剛好前兩天寫過一個小demo:Color Not


濾鏡是對圖片有效果,但是如果背景是純色不是圖片呢,可以用濾鏡實現嗎


推薦閱讀:

怎麼學習前端開發?求推薦學習路線?
HTML5 有哪些讓你驚艷的 demo?
有哪些不錯的前端開發博客?
為什麼不能在 EDM 模版中使用 DIV ?

TAG:前端開發 | CSS | HTML5 | iOSLiveBlur |