轉自IMWeb社群,作者:zzbozheng,原文連結
9月13日凌晨終於等來了萬眾矚目的蘋果新品釋出會,相信很多小夥伴們都期待新 iphone 可以剪掉劉海鬍子,但萬萬沒想到的是等來了三款不同的尺寸的 iphone x ,我的天,等了這麼久你給我看這個?碼農慌得一批滿地找新 iphone 的邏輯畫素,然後想著怎麼相容這劉海和鬍子。
以往的做法
其實對於 web 前端來說,劉海在絕大多數的場景下是可以不用處理的,因為 safari 或客戶端(微信,手Q等)的 statusBar 已經替我們抹平了頂部劉海,我們只需要關心底部的那條黑色的鬍子,因為如果頁面底部有按鈕的話,就會被鬍子給擋住,以往我們相容過 iphone x 的下巴,但現在回想起來不是正確的做法。我們之前是這麼處理的:
首先在 <html>
中加入對應的 className:has-bottombar
<html class="has-bottombar">
<head></head>
<body></body>
</html>
複製程式碼
再配上對應的 css:
@media only screen and (-webkit-device-pixel-ratio: 3) and (device-height: 812px) and (device-width: 375px) {
.has-bottombar {
height: 100%;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding-bottom: 34px;
}
.has-bottombar:after {
content: '';
z-index: 9999;
position: fixed;
left: 0;
bottom: 0;
width: 100%;
height: 34px;
background: #fff;
}
}
複製程式碼
這裡的處理方法是使用了媒體查詢 media query 按照 iphone x 的尺寸(375px * 812px)做特殊處理,主要做兩件事情:
1、給 html 底部預留 34px 的間距,讓頁面裡面的內容距底部保持 34px 的間距,從而避開了鬍子的遮擋。
2、建立一個 after
偽類通過設定 position: fixed
定位到頁面底部,並設定成白色,這一處理主要是遮擋住頁面背景色。
效果如下圖:
這樣只是解決了底部鬍子的問題,我們試著橫屏看看:
這裡有個很明顯的問題:頁面左邊的文字被劉海遮擋。
在 safari 往上段滑動一小段距離,可以看到當 safari 的底部操作欄出現後,頁面依然會保留著距底部的 34px 空白。
這些處理如果在9月13日之前是問題不大的,但在 9月13日 之後前端開發的同學頭就大了,因為新的三款 iphone 尺寸都不一樣(邏輯畫素 xr: 375 * 812; xs: 414 * 896; xs max: 414 * 896;)於是,開始奔命於修改 media query。。。如果明年又多幾個尺寸那就會是沒完沒了的改改改。
正確的姿勢
在 ios 11 中我們可以使用 viewport-fit=cover
+ safe-area-inset-*
。
那麼是不是 ios11 以下就用不了這些了呢?是的,但你見過 iphone x+ 有 ios 11以下的嗎? 所以我們可以愉快的搞下去。
開始之前我們先了解什麼是 safe area,簡單的來說就是除了劉海和鬍子以外的區域為安全區域:
關於 viewport-fit
viewport-fit 有3個值:
contain: 可視視窗完全包含網頁內容(左圖)
cover:網頁內容完全覆蓋可視視窗(右圖)
auto:預設值,跟 contain 表現一致
如何決定 viewport-fit 值?我們要考慮一些問題:
1、在非矩形顯示器上設定 viewport 邊界時,Viewport邊界框(Viewport Bounding Box)的面積大於顯示區域,導致了剪下區域
2、如果要保證Web頁面的任何部分都沒有隱藏,不想讓Web頁面在可讀性上變得很小,那麼最好將viewport-fit設定為cover,並在考慮剪下部分時實顯示頁面。
3、還有另一個考慮是,當我們設定 viewport-fit:contain,也就是預設的時候時,設定 safe-area-inset-* 等 css 屬性時不起作用的。 點選這裡瞭解更多關於 viewport-fit
關於 safe-area-inset-*
各種 iphone x 都是不規則形狀,我們如何控制頁面元素到安全區域呢?apple 把安全區域的位置通過 css 屬性提供給了開發者,它們可以通過CSS的constant( )函式來完成:
constant(safe-area-inset-top)
:在Viewport頂部的安全區域內設定量(CSS畫素)
constant(safe-area-inset-bottom)
:在Viewport底部的安全區域內設定量(CSS畫素)
constant(safe-area-inset-left)
:在Viewport左邊的安全區域內設定量(CSS畫素)
constant(safe-area-inset-right)
:在Viewport右邊的安全區域內設定量(CSS畫素)
簡單來說我們可以通過 constant( )
可以獲取到非安全邊距,再結合 padding
或 margin
來控制頁面元素避開非安全區域。 Webkit在iOS11中新增CSS Functions: env( )替代constant( ),文件中推薦使用env( ),而 constant( ) 從Safari Techology Preview 41 和iOS11.2 Beta開始會被棄用。在不支援env( )的瀏覽器中,會自動忽略這一樣式規則,不影響網頁正常的渲染。為了達到最大相容目的,我們可以 constant( ) 和 env( ) 同時使用。
.yourFooterClass {
padding-bottom: constant(safe-area-inset-bottom); /* iOS 11.0 */
padding-bottom: env(safe-area-inset-bottom); /* iOS 11.2 */
}
複製程式碼
本文為了簡潔只寫 env( )。
實踐一波
一、設定網頁在可視區域的佈局方式
新增 viweport-fit 屬性,使得頁面內容完全覆蓋整個視窗:
<meta name="viewport" content="width=device-width,initial-scale=1.0,viewport-fit=cover">
複製程式碼
二、讓主體內容控制在安全區域內
假設我們的底部按鈕高度是50px:
body {
padding-top: env(safe-area-inset-top);
padding-right: env(safe-area-inset-right);
padding-bottom: 50px; /* 相容不支援 env( ) 的裝置 */
padding-bottom: calc(env(safe-area-inset-bottom) + 50px); /* 在 iphone x + 中本句才會生效 */
padding-left: env(safe-area-inset-left);
}
複製程式碼
有兩個關鍵點:
1、寫在前面的 padding-bottom: 50px
為了相容沒有底部鬍子的裝置,讓主體內容偏移出底部按鈕的高度,避免按鈕遮擋內容。
2、padding-bottom: calc(env(safe-area-inset-bottom) + 50px);
計算 底部非安全區域距離
與 底部按鈕高度
之和 來做為 padding-bottom
值,如果裝置支援 env,那麼 calc 會計算出一個合法的值,本句的優先順序則最高,會覆蓋前面的 padding-bottom: 50px
。否則 calc 會計算出一個不合法的值,則本句宣告不會生效。這樣在不支援 env 裝置中也可以達到相容的目的。
目前到這,在橫屏場景下左側的內容就不會被劉海遮擋住了:
三、底部按鈕的處理
首先給底部按鈕一個外層容器 .btn-container
,設定樣式時其中有幾點比較關鍵:
1、設定padding-bottom: env(safe-area-inset-bottom);
增加一個 padding 值,讓底部向外擴充套件一個非安全區域的距離。
2、設定background: #FFF
讓整個 .btn-container
背景為白色(包括剛新增的 padding-bottom 的區域)這樣就可以遮擋住了底部內容。
3、設定 box-sizing: content-box;
,因為在通常情況下 css 在 reset 階段一般都設定了 * {box-sizing: border-box;}
這樣一來設定 padding 就不能向外擴充套件距離了,所以在這裡我們要把他改回 content-box
。
.btn-container {
box-sizing: content-box;
height: 50px;
line-height: 50px;
color: #fff;
position: fixed;
bottom: 0;
left: 0;
right: 0;
text-align: center;
background: #FFF;
padding-bottom: env(safe-area-inset-bottom);
}
.btn {
width: 100%;
height: 50px;
line-height: 50px;
background-color: #00c340;
border: none;
}
複製程式碼
看看效果:
在 safari 中,頁面往上稍滑動一點,出現 safari 的操作欄後,底部按鈕依然會緊貼著操作欄,非常有靈性:
處理起來一切都顯得 簡潔優雅細膩。
最後
如果相容劉海和鬍子需要滿地找邏輯畫素,滿地找新 iphone,很可能是沒有掌握正確的姿勢。
另外,發現在橫屏場景下有一個比較有趣的效果,大家可以瞭解一下,但在實際業務中應該不需要做得這麼花哨:
藉助CSS Shapes實現元素滾動自動環繞iPhone X的劉海