2019-12-10 15:45:26
背景:
最近遇到一個(gè)看似常規(guī)的H5需求载城,是App內(nèi)嵌的一個(gè)功能模塊最铁,看樣子跟往常一樣重復(fù)造輪子就OK了讯赏,客戶端開(kāi)個(gè)Webview加載頁(yè)面即可。
正常我們遇到最多的是下面這種類型:
這種的話一般是封裝一個(gè)Webview包含返回+標(biāo)題+分享功能冷尉,然后加載H5即可漱挎,返回即關(guān)閉Webview,標(biāo)題是讀取網(wǎng)頁(yè)的Title屬性雀哨,分享是調(diào)起客戶端的分享彈窗磕谅。
然是這次的H5有點(diǎn)不尋常的東西:
- 導(dǎo)航欄除了返回鍵、title雾棺、右側(cè)的操作菜單(進(jìn)入另一個(gè)H5頁(yè))膊夹,在title還有一個(gè)操作項(xiàng)?,用于點(diǎn)擊彈出說(shuō)明框捌浩。
-
有一個(gè)穿透狀態(tài)欄和導(dǎo)航欄的背景
大概長(zhǎng)下面這樣:
向上面的這種復(fù)雜頁(yè)面一般是客戶端做的放刨,但是!J取进统!
因?yàn)榉N種原因拓诸,最后商量用H5做。那看到這樣的設(shè)計(jì)圖麻昼,機(jī)智的攻城獅們一般會(huì)跟產(chǎn)品爭(zhēng)論一番討論說(shuō)你這背景圖做不了,只能到導(dǎo)航欄以下馋辈,并且你這個(gè)問(wèn)號(hào)得移到其他地方bulabulabula抚芦。。迈螟。
然而作為一名專業(yè)的攻城獅叉抡,我們當(dāng)然是奔著最佳的視覺(jué)感官+用戶體驗(yàn)去的,遇到問(wèn)題要克服之答毫!
那么確定100%還原設(shè)計(jì)圖后褥民,首先想到的一個(gè)方法是和雙端定義一系列協(xié)議,包括設(shè)置全屏背景圖洗搂、在title后面加操作按鈕(及隱藏方法消返,因?yàn)榈狡渌?yè)面就沒(méi)了),在右側(cè)加自定義的菜單耘拇,點(diǎn)擊后可跳轉(zhuǎn)其他頁(yè)面撵颊。這個(gè)看著就很麻煩,涉及到一系列的交互想想就頭疼惫叛,還不如直接原生寫(xiě)的痛快一點(diǎn)倡勇。和客戶端你同學(xué)討論后他們果然面露難色,在我說(shuō)完第二秒就否決的這種做法嘉涌,原因很簡(jiǎn)單:
1妻熊、交互太復(fù)雜
2、擴(kuò)展性太差仑最,下次H5的設(shè)計(jì)換個(gè)樣子又得加新交互
最終決定采用全屏Webview的形式扔役,整個(gè)頁(yè)面交給H5控制,這樣不管頁(yè)面設(shè)計(jì)成什么樣都能實(shí)現(xiàn)警医,什么全屏背景厅目,設(shè)么導(dǎo)航啦加各種東西通通不在話下。于是愉快的開(kāi)發(fā)開(kāi)始了法严。
然鵝在打碼到一半的時(shí)候我意識(shí)到一個(gè)問(wèn)題:雙端的狀態(tài)欄高度不一致损敷,并且現(xiàn)在還有劉海屏存在?? 這可腫么辦?
一深啤、IOS適配
首先對(duì)于IOS來(lái)說(shuō)拗馒,喬幫主整的還是比較規(guī)范的,畢竟IOS閉源系統(tǒng)只能跑在Apple硬件上溯街,設(shè)備型號(hào)有限诱桂,已知各機(jī)型尺寸如下:
注: 這里獲取到的px值跟web中的px雖然單位一樣洋丐,但并不是我們需要的值!;拥取友绝!Web所需的px實(shí)際為IOS中的pt值...,px轉(zhuǎn)pt需要根據(jù)設(shè)備的ppi(Pixels Per Inch: 像素密度)進(jìn)行轉(zhuǎn)換:
px: pixel 像素肝劲,是屏幕上的顯示的基本點(diǎn)迁客,他并不是長(zhǎng)度單位,這個(gè)點(diǎn)可以很大辞槐,也可以很小掷漱。點(diǎn)小的話就很清晰,我們稱之為“分辨率高”榄檬,反之就是“分辨率低”卜范。所以像素是一個(gè)相對(duì)單位。
pt: point 準(zhǔn)確的說(shuō)法是一個(gè)專用印刷單位“鎊”鹿榜,大小為1/72英寸海雪,是一個(gè)長(zhǎng)度單位。也是絕對(duì)長(zhǎng)度舱殿。
可以看到ios中的px轉(zhuǎn)pt根據(jù)設(shè)備的ppi大概是3:1/2:1/1:1轉(zhuǎn)換喳魏。
轉(zhuǎn)換完可以看到:
- 4.7寸6、6s怀薛、7刺彩、8,狀態(tài)欄高度為20pt枝恋,導(dǎo)航欄高度為44pt.
- 5.5寸的6p创倔、6sp、7p焚碌、8p畦攘,狀態(tài)欄高度為18pt,導(dǎo)航欄高度為44pt.
- 擁有劉海屏的X十电、XR知押、XS、XS MAX鹃骂、11等一系列劉海屏台盯,狀態(tài)欄高度為44pt,導(dǎo)航欄高度為44pt.
不難發(fā)現(xiàn):
- 導(dǎo)航欄 高度所有機(jī)型都為44pt畏线;
- 狀態(tài)欄 高度大致可以根據(jù)是否為劉海屏分為兩類静盅。沒(méi)有劉海屏的大小機(jī)型分別為18和20pt,可以近似的看成都是20pt來(lái)處理寝殴,問(wèn)題不大蒿叠,有劉海屏的則統(tǒng)一為44pt高明垢,跟導(dǎo)航欄高度相同。
適配方案:
iOS端的適配方案有兩種:Apple官方適配方案市咽、機(jī)型區(qū)分適配痊银、jsBridge方案
Apple官方適配方案:
1、在糞叉之后引入了一個(gè)新概念:“safe area(安全區(qū)域)”施绎,安全區(qū)域指屏幕內(nèi)不受圓角溯革、齊劉海、底部小黑條等元素影響的可視窗口粘姜。如下圖:
2、同時(shí)熔酷,從iOS11開(kāi)始孤紧,為了適配劉海屏,Apple公司對(duì)HTML的viewport meta標(biāo)簽做了擴(kuò)展
<meta name="viewport" content="viewport-fit=cover">
viewport-fit=cover
可設(shè)置為auto
, contain
, cover
三種狀態(tài)拒秘,這里我們重點(diǎn)使用cover
值号显,指頁(yè)面完全充滿屏幕。
3躺酒、iOS11同時(shí)新增了一個(gè)特性押蚤,constant(safe-area-inset-*),這是Webkit的一個(gè)CSS函數(shù)羹应,用于獲取安全區(qū)域與邊界的距離揽碘,有四個(gè)預(yù)定義的變量(單位px):
- safe-area-inset-left:安全區(qū)域距離左邊界距離,橫屏?xí)r適配
- safe-area-inset-right:安全區(qū)域距離右邊界距離园匹,橫屏?xí)r適配
- safe-area-inset-top:安全區(qū)域距離頂部邊界距離雳刺,豎屏下劉海屏為44px,iphone6系列20px裸违,豎屏劉海適配關(guān)鍵
- safe-area-inset-bottom:安全區(qū)域距離底部邊界距離掖桦,豎屏下為34px,豎屏小黑條適配關(guān)鍵
這樣適配方案就比較明確了:
- 首先通過(guò)設(shè)置
<meta name="viewport" content="viewport-fit=cover">
讓頁(yè)面充滿全屏 - 通過(guò)Webkit內(nèi)置的CSS函數(shù)供汛,獲取安全區(qū)域與各邊之間的間距枪汪,然后通過(guò)padding/margin/絕對(duì)定位等方式,讓頁(yè)面元素展示在安全區(qū)域內(nèi)怔昨。
注: Webkit在iOS11中新增CSS Functions: env( )替代constant( )雀久,文檔中推薦使用env( ),而 constant( ) 從Safari Techology Preview 41 和iOS11.2 Beta開(kāi)始會(huì)被棄用趁舀。在不支持env( )的瀏覽器中岸啡,會(huì)自動(dòng)忽略這一樣式規(guī)則,不影響網(wǎng)頁(yè)正常的渲染赫编。為了達(dá)到最大兼容目的巡蘸,我們可以 constant( ) 和 env( ) 同時(shí)使用奋隶。
padding-top: constant(safe-area-inset-top); /* iOS 11.0 */
padding-top: env(safe-area-inset-top); /* iOS 11.2 */
最終適配代碼如下:
使用@supports
查詢機(jī)型是否支持constant() / env()
實(shí)現(xiàn)兼容代碼隔離,個(gè)別安卓也會(huì)成功進(jìn)入這個(gè)判斷悦荒,因此加上-webkit-overflow-scrolling: touch
的判斷可以有效規(guī)避安卓機(jī)唯欣。
@supports ((height: constant(safe-area-inset-top)) or (height: env(safe-area-inset-top))) and (-webkit-overflow-scrolling: touch) {
.fullscreen {
/* 適配齊劉海 */
padding-top: 20;
padding-top: constant(safe-area-inset-top);
padding-top: env(safe-area-inset-top);
/* 適配底部小黑條 */
padding-bottom: 0;
padding-bottom: costant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
}
機(jī)型區(qū)分適配
這個(gè)就比較簡(jiǎn)單粗暴無(wú)腦了。因?yàn)槟壳笆忻嫔弦延械腁pple手機(jī)尺寸我們都是已知的搬味,那剩下的就是css中的media適配了:
/* iphone x / xs / 11 pro*/
@media only screen and (device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) {
...
}
/* iphone xr / 11 */
@media only screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) {
...
}
/* iphone xs max / 11 pro max */
@media only screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) {
...
}
.....
emmmmmm... 工作量大了點(diǎn)境氢,另外每年9月份發(fā)布會(huì)后要及時(shí)更新代碼??
jsBridge方案
如果你跟客戶端小哥哥的關(guān)系比較好的話,就用這種方案吧??碰纬,讓客戶端寫(xiě)個(gè)方法獲取狀態(tài)欄高度萍聊,然后在頁(yè)面加載的時(shí)候通過(guò)jsbridge調(diào)用獲取到狀態(tài)欄高度,然后設(shè)置頁(yè)面樣式即可悦析。
好了寿桨,鄙人想到的iOS適配方案到此為止。
二强戴、Android適配方案
整完相對(duì)規(guī)范的iOS亭螟,開(kāi)源的Android就相當(dāng)眼花繚亂了,機(jī)器廠商百花齊放骑歹,各廠商的機(jī)型也是眼花繚亂预烙。Android機(jī)型成百上千,適配方案反而變的簡(jiǎn)單了5烂摹1獾А!why? 因?yàn)橹挥幸环N方案:JSBridge
像上述iOS的適配方案中最域,官方適配方案Android肯定是么得了也糊,畢竟機(jī)型太多,搞不了官方規(guī)范羡宙。其次就是CSS media 查詢精準(zhǔn)適配狸剃,如果你的應(yīng)用只針對(duì)于少數(shù)機(jī)型,那這種方案還是可以用用的狗热,倘若不是那就拜拜了您嘞钞馁。
jsBridge方案
同iOS,客戶端獲取狀態(tài)欄高度后匿刮,H5通過(guò)JSBridge交互拿到狀態(tài)欄高度僧凰,設(shè)置頁(yè)面樣式避開(kāi)齊劉海區(qū)域。