相容iphone x劉海的正確姿勢

騰訊IMWeb團隊發表於2018-11-12

轉自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 定位到頁面底部,並設定成白色,這一處理主要是遮擋住頁面背景色。
效果如下圖:

相容iphone x劉海的正確姿勢

這樣只是解決了底部鬍子的問題,我們試著橫屏看看:
相容iphone x劉海的正確姿勢
這裡有個很明顯的問題:頁面左邊的文字被劉海遮擋。
相容iphone x劉海的正確姿勢

在 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,簡單的來說就是除了劉海和鬍子以外的區域為安全區域:

相容iphone x劉海的正確姿勢

關於 viewport-fit

viewport-fit 有3個值:
contain: 可視視窗完全包含網頁內容(左圖)
cover:網頁內容完全覆蓋可視視窗(右圖)
auto:預設值,跟 contain 表現一致

相容iphone x劉海的正確姿勢

如何決定 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( )函式來完成:

相容iphone x劉海的正確姿勢

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( ) 可以獲取到非安全邊距,再結合 paddingmargin 來控制頁面元素避開非安全區域。 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 裝置中也可以達到相容的目的。

目前到這,在橫屏場景下左側的內容就不會被劉海遮擋住了:

相容iphone x劉海的正確姿勢

三、底部按鈕的處理

首先給底部按鈕一個外層容器 .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;
}
複製程式碼

看看效果:

相容iphone x劉海的正確姿勢

在 safari 中,頁面往上稍滑動一點,出現 safari 的操作欄後,底部按鈕依然會緊貼著操作欄,非常有靈性:
相容iphone x劉海的正確姿勢

處理起來一切都顯得 簡潔優雅細膩。

最後

如果相容劉海和鬍子需要滿地找邏輯畫素,滿地找新 iphone,很可能是沒有掌握正確的姿勢。
另外,發現在橫屏場景下有一個比較有趣的效果,大家可以瞭解一下,但在實際業務中應該不需要做得這麼花哨:

相容iphone x劉海的正確姿勢

藉助CSS Shapes實現元素滾動自動環繞iPhone X的劉海

相關文章