移動端優雅佈局實踐

移動端優雅佈局實踐

前言:移動端有非常多的坑,佈局首當其衝。

背景

移動端應用有各種複雜的頁面需求,不僅要解決單屏、多屏、固定頭部或底部等多個場景,還要兼容ios和Android內核,在經歷了項目實戰(手機模式打開)過後,總結出了一些經驗,在這裏和大家分享一下。

這篇文章是基於 →
Next輕量級框架與主流工具的整合
最新的代碼在這裏 →
next-mobile-complete-demo

心路歷程

首先,需要實現的首頁類似於app應用。

截圖示例

  • 第一站:統一flex佈局的坑

    flex教程

    首頁如上面的圖片所示,然後偷了個懶,直接用了antd-mobile的tab標籤欄,它需要指定容器高度。於是,在項目最開始的時候直接通過js將容器設置爲瀏覽器html窗口的高度:

// html高度 = body高度 = 主容器高度
doc.body.style.height = docEl.clientHeight + 'px';

這樣做也有許多好處:縱向佈局十分方便,不管是tab標籤欄、tab標籤頁、頭部固定元素或者底部固定元素實現起來都很簡單;也能很簡單就能實現元素居中對齊、兩端對齊、自動分配空間等;同時也避免了Android輸入框引起傳統佈局的問題。

不過這裏有個唯一的不好的地方就是兼容不了ios的前進返回的操作欄和上下滾動回彈:

  • 不能在滾動時隱藏前進返回的操作欄、
  • 在上下滾動時容易觸發頁面的回彈效果,造成滾動卡頓。
這裏補充一下:在ios上如果以正常流佈局,內容超過一定高度時,向下滾動會隱藏底部的前進返回欄,向上滾動的時候再顯示出來。當滾動到底部或者頂部時,再繼續拉動頁面,會有一個回彈的效果。

這兩個問題極大的降低了ios的用戶體驗,又恰逢項目間隔期,有大把的時間,於是被推着到了佈局優化上面。

  • 第二站:尋找良好用戶體驗的佈局案例

這裏我們在尋找的過程中發現兩個具有代表性的移動端應用:

  1. bilibili的m站騰訊新聞

    它用的是傳統式流佈局,頭部和底部fixed固定,所有的內容全部向下平鋪。

  2. 花瓣網H5

    它採用的是設置主容器的position屬性爲absolute來脫離文檔流的形式。

這兩種佈局方式在ios上都用戶體驗極好。但同時也發現他們都存在的一些問題,比如:登錄頁面明明不足一屏,卻依然存在滾動;沒有兼容iPhone X的安全域;彈窗滾動穿透等等。

如果能將這兩種佈局和flex進行整合一下,聚合各自的優點,基本上能打造一個用戶體驗和兼容性都令人滿意的移動端應用了。

那麼,如何基於現有的flex佈局去整合這兩種佈局又成了一個問題。

  • 第三站:基於flex調整佈局結構

在調整之前,我的預期是這樣的:去掉外層高度限制,去掉縱向flex佈局(除極少數單屏頁面),將頂部、底部固定和彈窗設置爲fixed

考慮到少數單屏頁面需要繼承html窗口的高度,於是採用了主容器脫離文檔流的方式。

調整過後dom結構是這樣的:

html > body > div#root > div.main-content(position: absolute)

只需要給main-content加上height: 100%,就可以滿足單屏頁面的需求。

好事多磨!

按照上面的想法進行改造過後又發現了新的問題:脫離文檔流過後,切換頁面,html會保持最後滾動的位置

  • 第四站:滾動條位置、滾動穿透、兼容iPhone X

  1. 解決滾動條位置被記錄的問題
    找了一下發現history有個scrollRestoration的屬性,它有兩個值,一個是默認值auto還有一個是manual。如果設置爲manual就可以手動設置滾動的位置。

    if ('scrollRestoration' in history) {
      history.scrollRestoration = 'manual';
    }

    然後在切換路由過後設置滾動的位置爲起始位置:

    Router.events.on('routeChangeComplete', () => {
    document.scrollingElement.scrollTop = 0;
    });

    這樣每次切換頁面都是從初始位置開始。

    這裏有點雞肋,前進後退也不會記錄滾動位置。如果需要前進後退記錄滾動的位置,就不能用這種脫離文檔流的形式,需要用body滾動的形式,也就是。
  2. 解決滾動穿透
    這個問題,需要針對有滾動的彈窗和無滾動的彈窗單獨處理。

    • 針對無滾動的彈窗,在彈窗彈出的時候禁用touchmove事件,隱藏的時候移除事件監聽。
    • 有滾動的彈窗,需要找到頁面的滾動的容器設置overflow:hidden
  3. 兼容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窗口高度 前進後退無法記錄滾動條位置
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章