IphoneX適配正確姿勢

IphoneX適配正確姿勢

寫在前面

距離18年9月iphonex發布以來已經快兩年了(所以對於iphonex機型的頭部劉海(sensor housing)和底部小黑條(Home Indicator)的內容本文不在做過多贅述了),相信還有一些同學為iphonex系列機型如何完美適配在發愁,筆者結合公司移動端h5項目和一些官方文檔做了一個總結,希望可以幫到大家。

預備知識

在開擼之前,我們需要了解一下安全區域、viewport-fit、env() 和 constant()三個必備的知識點

安全區域

大家應該能看懂safe area是安全區域的意思吧?那顧名思義,如下圖所示,安全區域就是指的不受頭部劉海以及底部小黑條影響的那一部分區域。
image
蘋果官網人機交互指南

viewport-fit

viewport-fit是 IOS 11 新增的特性,關於viewport-fit的枚舉值介紹如下:

  • contain: 可視窗口完全包含網頁內容(左圖)
  • cover:網頁內容完全覆蓋可視窗口(右圖)
  • auto:默認值,跟 contain 表現一致

left1.png
right1.png

關於viewport-fit更詳細介紹

env() 和 constant()

各種 iphone x 都是不規則形狀,我們需要把我們的頁面內容控制在之前說的安全區域之內,那怎麼把頁面的頂部和底部空出來呢?不得不說apple挺貼心的,他們已經把安全區域的位置資訊通過css常量的方式暴露給了開發者,這些css常量需要用env() 和 constant()這兩個函數來包裹就可以拿到了。具體可以看這個issue

安全區域位置資訊常量值

  • safe-area-inset-top:從視口頂部開始的安全區域插入量(以CSS像素為單位)。
  • safe-area-inset-bottom:從視口底部開始的安全區域插入量(以CSS像素為單位)。
  • safe-area-inset-left:從視口左側開始的安全區域插入量(以CSS像素為單位)。
  • safe-area-inset-right:從視口右側開始的安全區域插入量(以CSS像素為單位)。

env() 和 constant()介紹

env() 和 constant()是IOS 11的新增特性,是兩個css函數,先來看看這兩個函數的兼容性:

image

我們可以看到在IOS 11.0-11.2是支援constant函數的,在11.3往後是廢棄了constant函數,取而代之的是env函數。

簡單示例

空出底部安全距離

padding-bottom: constant(safe-area-inset-bottom);  // 兼容 11.0 < iOS < 11.2
padding-bottom: env(safe-area-inset-bottom);  // 兼容 iOS >= 11.2

注意點

  • 需要設置viewport-fit=cover,安全區域位置資訊才有;
  • 寫的時候需要constant和env函數都寫上,以達到可以兼容所有IOS 11系統;

小結

需要注意使用安全區域位置資訊的前置條件是設置viewport-fit=cover,然後上述所說的資訊屬於IOS 11新增內容,iphonex出廠系統是大於等於11.0的,所以可以放心大膽的去用來做iphonex的兼容。

正確姿勢

看完前面以後,大家的一些奇怪的知識已經具備了,接下來就開始正式進入適配iphonex系列機型環節。當然,看完下面以後我們就會用最完美最簡潔的姿勢去進行適配了,不要眨眼,go~

前置條件

設置viewport-fit=cover

<meta name="viewport" content="width=device-width,viewport-fit=cover">

需要適配的iphonex系列機型「容器」

我們的移動端h5頁面一般無非在四個「容器」中打開:微信、網頁、App、小程式。所以我們需要針對這四個「容器」對我們的頁面做一些適配以便在iphonex系列機型中完美展現妾身的舞姿。

在微信、小程式、網頁中的適配

頭部

因為在這些「容器中」,頭部都已經由「容器」給我們適配好了(懂王自然懂),所以我們只需要關注底部即可。

底部

姿勢:頁面整體底部空出安全距離(不同的項目布局方式不同,視情況決定加在哪個地方更加合理(page,basicPage)):

body {
  box-sizing: border-box;
  padding-bottom: constant(safe-area-inset-bottom);
  padding-bottom: env(safe-area-inset-bottom);
}

在App中的適配

頭部

頭部兼容我們需要在自己項目的導航頭組件下手,思路就是給導航頭加上頂部安全距離,避免導航頭頂到劉海裡面。

  • 判斷在ios並且處在app環境中的時候加一個特定的類名,比如:ipx-head-nav
  • 給ipx-head-nav加一個padding-top值空出來頂部安全距離
.ipx-head-nav {
  padding-top: 20px; // iphonex系列機型之前頂部安全距離均為20px
  padding-top: constant(safe-area-inset-top);
  padding-top: env(safe-area-inset-top);
}

padding-top為20px去兼容iphonex以及IOS 11系統之前的機型,constant和env函數去適配iphonex以及IOS 11系統之後的機型。

底部

和在微信、小程式、網頁中的底部適配姿勢一致,統一姿勢。

一些特殊場景的處理

吸底(bottom === 0)的按鈕

建議吸底按鈕都改為fixed定位,然後我們用這個姿勢去適配:

.btn {
  position: fixed;
  bottom: 0; // 當constant和env函數都不支援的時候,這個會生效
  bottom: constant(safe-area-inset-bottom);
  bottom: env(safe-area-inset-bottom);
  &:after {
    content: ' ';
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: #ffffff;
    height: constant(safe-area-inset-bottom);
    height: env(safe-area-inset-bottom);
  }
}

因為在iphonex上,按鈕bottom為底部安全距離,那和最下面就會有一段鏤空的空檔,所以還需要把這個空檔給補上。

思路:

  1. 按鈕bottom值先適配iphonex;
  2. 添加一個新的元素補到空檔的位置,高度就是安全距離的高度。

fixed定位的非完全吸底(bottom !== 0)元素,比如「返回頂部」按鈕

在這裡我們假設有一個需求,一個「返回頂部」的按鈕,需要距離底部30px,還需要適配iphonex,那麼我們就可以使用下面的姿勢:

.back-top-btn {
  bottom: 30px;
  bottom: calc(30px + constant(safe-area-inset-bottom));
  bottom: calc(30px + env(safe-area-inset-bottom));
}

在不支援constant和env函數的系統中,bottom計算出來的值是無效的,bottom: 30px會生效。

小福利

相信大家現在已經掌握了適配iphonex系列機型的正確姿勢了,如果你的項目里是使用scss去編寫樣式的,在這裡送大家3個牛逼的姿勢秘籍,這麼簡單的姿勢應該一看就能懂是怎麼用的,不懂的話可以在評論區留言提問:

// ipx系列底部padding值
@mixin iphonex-padding-bottom($paddingBottom: 0px) {
  padding-bottom: $paddingBottom;
  padding-bottom: calc(#{$paddingBottom} + constant(safe-area-inset-bottom));
  padding-bottom: calc(#{$paddingBottom} + env(safe-area-inset-bottom));
}

// ipx系列fixed定位底部bottom值
@mixin iphonex-fixed-bottom($bottom:0px) {
  bottom: $bottom;
  bottom: calc(#{$bottom} + constant(safe-area-inset-bottom));
  bottom: calc(#{$bottom} + env(safe-area-inset-bottom));
}

// ipx系列fixed定位bottom為0的處理函數
@mixin iphonex-fixed-bottom-zero($backgroundColor: #ffffff) {
  @include iphonex-fixed-bottom();
  &:after {
    content: ' ';
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: $backgroundColor;
    height: constant(safe-area-inset-bottom);
    height: env(safe-area-inset-bottom);
  }
}

寫在最後

以上分享的姿勢是筆者總結出來的比較通用的解決方案,但方案並不是唯一的,只是希望能給大家提供一種解決思路,讓自己的應用更加完美。最後當然是要感謝大家的閱讀啦,thank you~

作者:渴望成為大牛的男人。本文首發地址://juejin.cn/post/6865873665104773128

Tags: