借助CSS Shapes實現元素滾動自動環繞iPhone X的劉海
一、iPhone X的劉海發型和衍生的交互
iPhone X造型上有個顯著的特質,就是有個明顯的劉海。
然后,也出現了一些酷酷的交互。
例如下面這個交互:
交互視頻效果戳這里體驗:http://t.cn/Rp01GKc
就是頁面滾動的時候,列表會自動繞著iPhone X的劉海排列。
看上面微博截圖的反應,好像覺得這個效果實現很難,實際上,CSS3里面針對這種特定形狀環繞的效果已經支持很久了,CSS3 Shapes和CSS3 Regions都是可以實現的,本文就將展示如何使用CSS3 Shapes實現元素內容在滾動的時候自動環繞iPhone X的齊劉海的效果。
二、CSS3 Shapes實現元素滾動自動環繞iPhone X頭部劉海效果
眼見為實先看效果,您可以狠狠的點擊這里:CSS3 Shapes實現列表環繞iPhone X劉海頭demo
滾動列表,可以看到類似下面gif的效果:

環繞齊劉海滾動實現原理
CSS Shapes中有個CSS屬性名為shape-outside,可以讓內聯元素以不規則的形狀進行外部排列,其語法如下(參考自MDN):
/* 關鍵字值 */ shape-outside: none; shape-outside: margin-box; shape-outside: content-box; shape-outside: border-box; shape-outside: padding-box; /* 函數值 */ shape-outside: circle(); shape-outside: ellipse(); shape-outside: inset(10px 10px 10px 10px); shape-outside: polygon(10px 10px, 20px 20px, 30px 30px); /* <url>值 */ shape-outside: url(image.png); /* 漸變值 */ shape-outside: linear-gradient(45deg, rgba(255, 255, 255, 0) 150px, red 150px);
shape-outside屬性要想生效,本身需要是浮動float元素。
本文demo效果實現使用的是shape-outside:polygon(),通過點坐標勾勒出和齊劉海形狀相似的多邊形形狀,CSS代碼為:
.shape {
float: left;
shape-outside: polygon(0 0, 0 150px, 16px 154px, 30px 166px, 30px 314px, 16px 326px, 0 330px, 0 0);
}
此時,后面沒有設置BFC(塊狀格式化上下文)的列表元素就會自動環繞這個形狀排列,也就是自動避開了齊劉海區域。
然后,只要搞個假的iPhone X的齊劉海圖片覆蓋在區域上就可以了。
至此,一個靜態的列表環繞齊劉海的效果就完成了。
下面關鍵的問題是如何讓滾動的時候,列表元素動態的跟著環繞呢?
由于shape-outside所在的元素是浮動元素,因此,必定會跟著容器一起滾動,我們需要的效果是我們所繪制的這個劉海區域需要是固定的,怎么辦?此時,我是借助JavaScript處理的。
原理很簡單,監聽容器的滾動事件,讓我們的shape-outside繪制的區域實時偏移滾動的大小。此時肉眼看上去的效果就是shape-outside區域永遠固定在了滾動容器clientHeight的中間。
整個效果就這么實現了,相關JS如下:
box.addEventListener('scroll', function () {
var scrollTop = box.scrollTop;
// 滾動偏移應用在shape-outside上
shape.style.shapeOutside = 'polygon(0 0, 0 '+ (150 + scrollTop) +'px, 16px '+ (154 + scrollTop) +'px, 30px '+ (166 + scrollTop) +'px, 30px '+ (314 + scrollTop) +'px, 16px '+ (326 + scrollTop) +'px, 0 '+ (330 + scrollTop) +'px, 0 0)';
});
更詳盡的代碼盡在demo頁面。
三、CSS Shapes環繞iPhone X劉海的其它更簡易方法
如果我們的技術選型是更看重簡單易懂,而不是資源消耗與占用,還可以使用shape-outside:url(image.png)語法實現類似的效果,其中'image.png'就是用來被環繞的圖片,環繞與否是基于計算alpha通道決定,用句簡單的話描述,就是沿著圖片非透明區域環繞。
由于使用url()的形狀計算是基于圖片元素,和inset(), circle(), ellipse()或者polygon()這些基礎形狀方法的計算性質不一樣,因此,可以直接使用垂直方向的margin進行偏移。這要比polygon()這樣實時計算坐標位置要好理解的多。
我們不妨看下CSS和JS代碼,如下:
.shape {
float: left;
shape-outside: url(liu-outside.png);
margin-top: 150px;
}
box.addEventListener('scroll', function () {
var scrollTop = box.scrollTop;
// 滾動偏移應用在margin-top上
shape.style.marginTop = (150 + scrollTop) + 'px';
});
可以看到,當我們滾動容器的時候,改變的就一個marginTop值就好了;而上面的 shape-outside:polygon()實現需要同時改變多個坐標值。
眼見為實,您可以狠狠的點擊這里:shape-outside url實現列表環繞iPhone X劉海demo
如果是iPhone手機,還可以掃下面碼體驗:
效果類似:

有個細節說明
這里有個細節需要說明下,那就是作為環繞區域的圖片和前面顯示的那個劉海圖片不是一張圖片,因為我們的劉海區域需要和后面的文字有一段的間隙,因此,url(liu-outside.png)中的這張'liu-outside.png'圖片是有特別的實色填充處理的(擴展右側環繞區域尺寸):
四、CSS Shapes的兼容性以及結束語
CSS Shapes的兼容性為Chrome瀏覽器和Safari瀏覽器(包括iOS)都是支持的,也就意味著我們是可以在iPhone上使用的,完美。只是需要注意的是在iOS10.2及其之前的版本,CSS Shapes的使用還是需要加webkit私有前綴的,但據說iPhone X至少默認iOS 11,而劉海頭交互效果就是針對iPhone X處理的,因此webkit私有前綴不加也沒關系。
本文這個例子可以看出知識廣度的重要性,如果我們深究最終效果實現使用的CSS和JS代碼,其實就幾行代碼而已,鍵盤敲一下,幾分鐘就結束了。
那為什么廣大前端一看到這個效果覺得牛,甚至認為“UI和前端已經哭暈在廁所”呢?其實就是不知道CSS3 Shapes和CSS3 Regions這些與環繞布局相關的CSS屬性。


浙公網安備 33010602011771號