最近寫小程序時(shí),遇到了 iPhoneX 底部小黑線與內(nèi)容重疊的問題,實(shí)際上是iPhoneX安全區(qū)域的適配問題,了解清楚這個(gè)問題花了挺多時(shí)間的,也實(shí)操出了結(jié)果,忍不住來總結(jié)總結(jié)。
前言
· 內(nèi)容與小黑線重疊情況說明
1.安全區(qū)域含義
2.微信小程序適配iPhoneX底部小黑條(Home Indicator)
(1)適配方案一:使用已知底部小黑條高度34px/68rpx來適配(不推薦)
(2)適配方案二:使用微信官方API,getSystemInfo()中的safeArea對(duì)象進(jìn)行適配(推薦)
(3)適配方案三:使用蘋果官方推出的css函數(shù)env()、constant()來適配 (推薦) 3.H5適配iPhoneX底部小黑條(Home Indicator) · 適配方案:使用蘋果官方推出的css函數(shù)env()、constant()來適配 (推薦)
在蘋果 iPhoneX 、iPhone XR等設(shè)備上,可以看到物理Home鍵被取消,改為底部小黑條替代home鍵功能。微信小程序和 h5 網(wǎng)頁(yè)需要針對(duì)這種情況進(jìn)行適配,否則可能會(huì)遇到底部按鈕或選項(xiàng)卡欄與底部黑線重疊的情況,如下圖。
想要解決內(nèi)容與小黑線重疊的問題,我們需要先了解清楚蘋果對(duì)于安全區(qū)域的定義。
安全區(qū)域指的是一個(gè)可視窗口范圍,處于安全區(qū)域的內(nèi)容不受圓角(corners)、齊劉海(sensor housing)、小黑條(Home Indicator)的影響。
看看蘋果官方給的這2張圖就明白了,中間藍(lán)色區(qū)域即為安全區(qū)域。也就是說,適配安全區(qū)域也就是讓小程序或者H5的內(nèi)容顯示在藍(lán)色區(qū)域部分。
同時(shí)安全區(qū)域是在IOS11之后并且是iPhoneX及以上機(jī)型才有的,所以需要適配的是這一類機(jī)型(為了方便,下文中統(tǒng)稱這類需要適配的機(jī)型為iPhoneX),更老的機(jī)型則不需要考慮適配問題。
三種方案:
這是比較老的方法,跟方案2、3比已經(jīng)不推薦了,大家可以了解了解,著急可以直接看方案2和3。
從網(wǎng)上了解到,iPhone底部的小黑條(Home Indicator)高度是34px,實(shí)際我也在真機(jī)確認(rèn)了是34px,所以可以根據(jù)該值,設(shè)置底部按鈕或選項(xiàng)卡的margin-bottom、padding-bottom、height等,或者添加一個(gè)div來占位小黑條的位置。
這樣做要有一個(gè)前提,需要判斷當(dāng)前機(jī)型是需要適配安全區(qū)域的機(jī)型。
2種方案:
已知市面上已有的帶安全區(qū)域的蘋果設(shè)備包括iPhone X、iPhone XR、iPhone XS Max、iPhone 11、iPhone 11 Pro、iPhone 11 Pro Max,所以可以直接從getSystemInfoSync()方法中拿到model屬性進(jìn)行判斷。iPhone系列微信還未適配手機(jī)的model返回值為unknown(iphone),也可以提前做適配。
let IPHONE_X = /iphone x/i let IPHONE_X_11 = /iphone 11/i let IPHONE_UNKNOWN = /unknown\(iphone\)/i //方法一:使用model判斷是否是IPhoneX及其他包含安全區(qū)域的機(jī)型手機(jī) const isIPhoneX = () => { let model = wx.getSystemInfoSync().model return (model.search(IPHONE_X) > -1 || model.search(IPHONE_X_11) > -1 || model.search(IPHONE_UNKNOWN) > -1) } //也可以使用正則表達(dá)式判斷 const isIPhoneXRegex = () => { let model = wx.getSystemInfoSync().model return (/iphone\sx/i.test(model) || (/iphone/i.test(model) && /unknown/.test(model)) || /iphone\s11/i.test(model)) } 復(fù)制代碼
這里使用 screenHeight 而不是 windowHeight ,因?yàn)?nbsp;bottom 是以屏幕左上角為原點(diǎn)開始計(jì)算的,所以需要的是屏幕高度,對(duì)比 screenHeight 和 bottom ,如果相等則說明不需要適配,不相等則需要適配。
**注意:**如果使用微信開發(fā)者工具中的模擬器,screenHeight和bottom始終是相等的,需要用真機(jī)來測(cè)試。
//方法二:使用wx.getSystemInfoSync()中的screenHeight和safeArea的bottom判斷 const isIPhoneX = () => { let screenHeight = wx.getSystemInfoSync().screenHeight let bottom = wx.getSystemInfoSync().safeArea.bottom return screenHeight !== bottom } 復(fù)制代碼
解決了如何判斷設(shè)備是iPhoneX的問題,就可以寫代碼了。
<view class="bottom-button {{isIpX ? 'view-IPX' : ''}}">底部按鈕</view> 復(fù)制代碼
step 1:使用上面講的方法先判斷是否是需要適配的iPhone機(jī)型 step 2:如果是需要適配的機(jī)型,使用safeArea中的bottom,得到安全區(qū)域底部縱坐標(biāo),然后使用screenHeight減去bottom就能得到小黑條的高度。保存到localstorage里面,全局都可以使用。
蘋果官方推薦使用 env() , constant() 來適配,建議使用該方案,不需要管數(shù)值具體是多少。這2個(gè)方法是什么呢?
因?yàn)槟繕?biāo)是需要對(duì)底部小黑條做適配,所以只需要關(guān)注 safe-area-inset-bottom 這個(gè)值。
而env()和constant()函數(shù)有個(gè)必要的 使用前提 ,當(dāng)網(wǎng)頁(yè)設(shè)置 viewport-fit=cover 的時(shí)候才生效,根據(jù)微信小程序的表現(xiàn)和我在實(shí)際真機(jī)測(cè)試時(shí)這兩個(gè)函數(shù)生效,推測(cè)小程序里的 viewport-fit 默認(rèn)是 cover 。
有一點(diǎn)要注意,在IOS11.2系統(tǒng)以前,可以使用constant()函數(shù),但是在IOS11.2系統(tǒng)以后,這個(gè)函數(shù)就被廢棄了,被env()函數(shù)替代了。官方原話如下:
The env() function shipped in iOS 11 with the name constant(). Beginning with Safari Technology Preview 41 and the iOS 11.2 beta, constant() has been removed and replaced with env(). You can use the CSS fallback mechanism to support both versions, if necessary, but should prefer env() going forward.
所以我們?cè)谧銎聊贿m配時(shí),需要這樣寫:
padding-bottom: constant(safe-area-inset-bottom); /*兼容 IOS<11.2*/ padding-bottom: env(safe-area-inset-bottom); /*兼容 IOS>11.2*/ 復(fù)制代碼
**注意:**env()和constant()需要同時(shí)存在,而且順序不能換。
在H5上適配安全區(qū)域就方便多了,采用viewport+env+constant方案。
viewport-fit 默認(rèn)有3個(gè)值:
contain和cover具體區(qū)別如下圖:
<meta name="viewport" content="width=device-width,initial-scale=1.0,viewport-fit=cover"> 復(fù)制代碼
同時(shí)設(shè)置env和constant代碼,同樣env()和constant()需要同時(shí)存在,而且順序不能換。
/* 可以通過增加padding-bottom來適配 */ padding-bottom: constant(safe-area-inset-bottom); /*兼容 IOS<11.2*/ padding-bottom: env(safe-area-inset-bottom); /*兼容 IOS>11.2*/ /* 可以通過margin-bottom來適配 */ margin-bottom: constant(safe-area-inset-bottom); margin-bottom: env(safe-area-inset-bottom); /* 或者改變高度*/ height: calc(55px + constant(safe-area-inset-bottom)); height: calc(55px + env(safe-area-inset-bottom)); 復(fù)制代碼
也可以在底部添加一個(gè)空白的div顏色塊來做適配。
可以使用 @supports 來隔離兼容樣式,當(dāng)瀏覽器支持 bottom: constant(safe-area-inset-bottom) 或者 bottom: env(safe-area-inset-bottom) 的時(shí)候, bottom-button 類就會(huì)新增 margin-bottom 的樣式
@supports (bottom: constant(safe-area-inset-bottom)) or (bottom: env(safe-area-inset-bottom)) { .bottom-button { margin-bottom: constant(safe-area-inset-bottom); margin-bottom: env(safe-area-inset-bottom); } } 復(fù)制代碼
以上就是我對(duì)iPhoneX安全區(qū)域(Safe Area)底部小黑條在微信小程序和H5適配的總結(jié)。