前言:移動端有很是多的坑,佈局首當其衝。
移動端應用有各類複雜的頁面需求,不只要解決單屏、多屏、固定頭部或底部等多個場景,還要兼容ios和Android內核,在經歷了項目實戰(手機模式打開)事後,總結出了一些經驗,在這裏和你們分享一下。html
這篇文章是基於 →
Next輕量級框架與主流工具的整合
最新的代碼在這裏 →
next-mobile-complete-demoios
首先,須要實現的首頁相似於app應用。git
→ flex教程
首頁如上面的圖片所示,而後偷了個懶,直接用了antd-mobile的tab標籤欄,它須要指定容器高度。因而,在項目最開始的時候直接經過js將容器設置爲瀏覽器html窗口的高度:github
// html高度 = body高度 = 主容器高度 doc.body.style.height = docEl.clientHeight + 'px';
這樣作也有許多好處:縱向佈局十分方便,不論是tab標籤欄、tab標籤頁、頭部固定元素或者底部固定元素實現起來都很簡單;也能很簡單就能實現元素居中對齊、兩端對齊、自動分配空間等;同時也避免了Android輸入框引發傳統佈局的問題。segmentfault
不過這裏有個惟一的很差的地方就是兼容不了ios的前進返回的操做欄和上下滾動回彈:瀏覽器
這裏補充一下:在ios上若是以正常流佈局,內容超過必定高度時,向下滾動會隱藏底部的前進返回欄,向上滾動的時候再顯示出來。當滾動到底部或者頂部時,再繼續拉動頁面,會有一個回彈的效果。
這兩個問題極大的下降了ios的用戶體驗,又恰逢項目間隔期,有大把的時間,因而被推着到了佈局優化上面。安全
這裏咱們在尋找的過程當中發現兩個具備表明性的移動端應用:antd
它用的是傳統式流佈局,頭部和底部fixed固定,全部的內容所有向下平鋪。app
它採用的是設置主容器的position屬性爲absolute來脫離文檔流的形式。框架
這兩種佈局方式在ios上都用戶體驗極好。但同時也發現他們都存在的一些問題,好比:登陸頁面明明不足一屏,卻依然存在滾動;沒有兼容iPhone X的安全域;彈窗滾動穿透等等。
若是能將這兩種佈局和flex進行整合一下,聚合各自的優勢,基本上能打造一個用戶體驗和兼容性都使人滿意的移動端應用了。
那麼,如何基於現有的flex佈局去整合這兩種佈局又成了一個問題。
在調整以前,個人預期是這樣的:去掉外層高度限制,去掉縱向flex佈局(除極少數單屏頁面),將頂部、底部固定和彈窗設置爲fixed。
考慮到少數單屏頁面須要繼承html窗口的高度,因而採用了主容器脫離文檔流的方式。
調整事後dom結構是這樣的:
html > body > div#root > div.main-content(position: absolute)
只須要給main-content加上height: 100%
,就能夠知足單屏頁面的需求。
好事多磨!
按照上面的想法進行改造事後又發現了新的問題:脫離文檔流事後,切換頁面,html會保持最後滾動的位置。
有可能出現滾動條位置被記錄的問題
找了一下發現history
有個scrollRestoration
的屬性,它有兩個值,一個是默認值auto
還有一個是manual
。若是設置爲manual
就能夠手動設置滾動的位置。
if ('scrollRestoration' in history) { history.scrollRestoration = 'manual'; }
而後在切換路由事後設置滾動的位置爲起始位置:
Router.events.on('routeChangeComplete', () => { document.scrollingElement.scrollTop = 0; });
這樣每次切換頁面都是從初始位置開始。
開發碰見的問題,這個demo中沒有出現。這裏有點雞肋,前進後退也不會記錄滾動位置。若是須要前進後退記錄滾動的位置,就不能用這種脫離文檔流的形式,須要用body滾動的形式,也就是。
解決滾動穿透
這個問題,須要針對有滾動的彈窗和無滾動的彈窗單獨處理。
overflow:hidden
兼容iPhone X
在meta標籤後增長viewport-fit=cover
<meta name="viewport" content="initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,viewport-fit=cover"/>
而後留出安全域距離
padding-bottom: 0.49rem; // 底部button的高度 padding-bottom: calc(0.49rem + constant(safe-area-inset-bottom)); padding-bottom: calc(0.49rem + env(safe-area-inset-bottom));
這裏須要注意些padding-bottom
的時候須要寫三個,第一個是爲了兼容Android。
總的來講flex佈局仍是帶了十分大的便利,尤爲是能根治居中、適配等一些老大難的問題。
每種佈局的方式都有必定的缺陷,到目前爲止尚未一種萬能的方案來解決移動端各類複雜的場景。仍是須要根據本身的需求還選擇使用哪一種實現方式。
*前面這三種方案各自的缺陷:
縱向flex佈局(不建議使用) | body流式平鋪(傳統) | absolute脫離文檔流(正在使用) |
---|---|---|
ios前進後退的操做欄沒法隱藏、回彈效果引發卡頓 | 內部容器沒法繼承html窗口高度 | 路由跳轉可能出現滾動條被記錄 |