如何針對iPhone X 設計網站?
這是一篇來自蘋果關於iPhone X適配的官方指南,希望可以幫助各位前端開發者做好iPhone X的適配。

下面關於安全邊距的內容於2017年10月20日有更新,跟進iOS 11.2 beta的一些變化。
在全面屏的iPhone X 上,不需要而外的代碼,Safari 可以非常完美的展示現有的網站。整個網站的內容都會自動地展示在一個“安全區域”內,並不會被四周的圓角或者“小劉海”遮擋住。
Safari使用頁面的背景色(一般就是<body>
或者<html>
元素的background-color
)來填充周圍空出的區域,與頁面的其他部分保持協調。這種方式可以解決網站大部分的問題。如果本身就是一個固定背景色上堆疊一些文字或者圖片的網站,默認的填充區域看起來會很協調。
不過還有一些網站——尤其是那些有橫向貫穿的導航條的網站,像下面這樣的就需要做一點額外的工作,使得在這種新的顯示下繼續利用全面屏的優勢,且不顯得突兀。 iPhone X Human Interface Guidelines詳細解釋了一些需要注意的設計準則, UIKit documentation也給出了一些Native App可以採用的機制來保證視覺效果。同樣,在網站這邊,也可以利用iOS 11 裡Safari 引入的特定API 來使用好全面屏顯示的優點。
下面的每個圖都可以點擊打開可對應的demo,方便大家查看效果和源碼。

全屏顯示
第一個新特性擴展了現有viewport
這個meta標記,添加了名字為viewport-fit
的屬性,用來控製網頁的安全邊距。 viewport-fit
在iOS 11上才有效。
viewport-fit
的默認值是auto
,效果如上圖,默認留出安全邊距。如果想要全屏顯示,需要將viewport-fit
設置為cover
。 meta 標記看上去像下面這樣:
<metaname='viewport'content='initial-scale=1, viewport-fit=cover’>
刷新頁面,導航欄擴展到了屏兩端,看起來舒服多了。但是,馬上我們就會發現系統默認讓出安全邊距是很有必要的:網頁內容被iPhone 的小劉海覆蓋了,底部的導航也好難使用。

安全邊距
接下來需要讓使用了viewport-fit=cover
之後界面還是可用的。我們需要有選擇地給那些包含重要訊息的元素加上內邊距,避免它們受到屏幕形狀的影響。這樣不但可以充分利用iPhone X 擴大的屏幕,也可以避免手機四個角、小劉海和退到主屏標誌的影響。

如何達到這個目標? iOS 11的WebKit引入了一個新的CSS函數—— env()
,還有四個預定義的環境變量。 —— safe-area-inset-left
, safe-area-inset-right
, safe-area-inset-top
,和safe-area-inset-bottom
。結合這兩個新東西,就可以在樣式中使用安全邊距。
env()
函數在iOS 11發布的時候用的名字是constant()
。 Safari Technology Preview 41和iOS 11.2 beta發布的時候,constant()
被替換成了env()
。可以利用CSS的降級機制同時支持這兩個版本的不同函數。但如果不考慮兼容性,往後就使用env()
。
env()
可以用在任何支持var()
的地方——舉個例子, padding
屬性中使用:
.post{padding:12px;padding-left:env(safe-area-inset-left);padding-right:env(safe-area-inset-right);}
在不支持env()
函數的瀏覽器中,這條CSS規則會被忽略。因此,針對每個使用env()
的地方,加一條CSS備用規則尤其重要。

借力min()
或者max()
橫豎屏兼容
本節說的特性都是Safari Technology Preview 41和iOS 11.2 beta上引入的新特性。
如果你已經給自己的站點添加了安全邊距,可能就會發現,指定了安全邊距後,無法再給元素指定一個最小邊距。如上面到例子,把12px
的左邊距換成env(safe-area-inset-left)
,當把手機豎起來,安全邊距變成了0px
,文字內容立馬就和手機邊緣粘在一起了。

為了解決這個問題,就需要在默認邊距和安全邊距中選擇較大值。我們可以使用Safari Technology Preview 新增的CSS函數min()或max()來實現。這兩個函數都接受任意個數字,返回其中最小或者最大值。兩個函數都可以使用在calc()
中,也可以互相嵌套,也允許在函數內使用計算(就如calc()
的那樣)。
使用max()
解決戰鬥:
@supports(padding: max(0px)) { .post { padding-left: max(12px, env(safe-area-inset-left)); padding-right: max(12px, env(safe-area-inset-right)); } }
別忘了使用@supports
來對min和max函數特性進行兼容性檢查,因為不是所有瀏覽器都支持這個特性。由於CSS對無效variable的處理,不要在@supports
查詢中使用variable。
手機處於豎屏狀態時, env(safe-area-inset-left)
取值為0px,因此max()函數的取值為12px。橫屏時, env(safe-area-inset-left)
因為小劉海的存在,會比較大,max()就會返回安全邊距,這樣就可以保證重要的內容總是可見。

經驗老到的Web 開發者可能碰到過像上看這樣的“CSS locks”原理,用來將CSS 屬性值限制在一個特定範圍內。 min()
和max()
可以讓這件事變得更簡單,對以後快速實現響應式設計將會非常有用。
譯註:CSS locks具體是什麼,不太理解,哪位大大給分享一下?
問題反饋
大家現在就可以開始適配viewport-fit和安全邊距了,可以使用iPhone X模擬器上的Safari來測試,這需要安裝Xcode 9 。歡迎你把利用上面特性來做兼容的方案分享給我們,也可以給我們提交問題和反饋,發郵件到[email protected] ,或者在Twitter上直接@webkit留言。碰到任何bug可以提到WebKit's bug tracker 。