web移動端布局的那些事兒

web移動端布局范疇很廣,其中比較基礎的幾個話題:

  • 移動端適配

  • 1px border

  • 基礎布局

本文主要分享這三個話題

一、移動端適配

提起移動端適配,大家想到的肯定是remflexible.js,本文要分享的方案是 vw + rem

對移動端適配不熟悉的同學,可以看看:

vw 是什么?

vw 是基于視圖(Viewport)的長度單位,而與Viewport相關四個單位有:

  • vw:Viewport's Width 簡寫,1vw 等于 window.innerWidth 的 1%

  • vh:Viewport's Height 簡寫,1vh 等于 window.innerHeight 的 1%

  • vmin:當前 vw 和 vh 中較小值

  • vmax:當前 vw 和 vh 中較大值

web移動端布局的那些事兒的圖1

常規的 rem 的適配方案(包括flexible),其實就是通過 js 動態計算,模擬 vw 的效果,過去使用這種方案主要原因是 vw 存在一定的兼容問題,不過對于現在而言,vw 也基本能滿足對兼容性的要求

web移動端布局的那些事兒的圖2

可以看到,Android 4.4 以上及 IOS 8.0 以上均已支持,所以現在我們可以直接使用 vw 來做移動端適配啦

vw + rem 方案

1、設置 html font-size 為 10vw
html {     font-size: 10vw; } 復制代碼
2、以750UI圖為例,在 css 中,直接使用UI圖上的長度值,單位設置為 px
.head {     width: 750px; } 復制代碼
3、引入 postcss-pxtorem 插件,配置如下:
require('postcss-pxtorem')({     rootValue: 75,     unitPrecision: 5,     propList: ['*'],     selectorBlackList: [],     replace: true,     mediaQuery: false,     minPixelValue: 0 }) 復制代碼

以上,就可以使用了 vw + rem 方案實現了移動端適配

4、引入 viewport-units-polyfill 解決兼容問題

為了保證在低版本的機型也能正常顯示頁面,可以引入 viewport-units-polyfill 來處理 vw 的兼容問題。

viewport-units-polyfill 其實是 viewport-units-buggyfill 的簡化版。

簡單介紹下 viewport-units-buggyfill 的實現思路:通過引入一段js,對于存在兼容問題的版本,遍歷頁面中所有的css,找到用到Viewport單位的css,將Viewport單位計算為 px 單位,并將新的css規則插到head或body中。

viewport-units-polyfill 則是在 viewport-units-buggyfill 基礎上做了些修改,主要是把大量的遍歷工作去掉,只針對 html font-size 做兼容處理(此適配方案只在 html font-size 中使用到vw)。去掉遍歷工作,大大優化了性能。

用法:直接將此 js 腳本放在頁面的 head 中即可

二、1px border

網上對 1px border 問題的解決方案很多,可以看看:再談Retina下1px的解決方案

本文分享的方案則是在使用 vw + rem 的適配方案基礎上,使用視圖縮放(Viewport scale)來解決 1px border 問題

實現

(function () {     var dpr = window.devicePixelRatio;     var scale = 1 / dpr;     var metaEl = document.querySelector('meta[name="viewport"]') || document.createElement('meta');     metaEl.setAttribute('name', 'viewport');     metaEl.setAttribute('content', 'width=device-width, initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no, viewport-fit=cover');     if (document.documentElement.firstElementChild) {         document.documentElement.firstElementChild.appendChild(metaEl);     } else {         var wrap = document.createElement('div');         wrap.appendChild(metaEl);         document.write(wrap.innerHTML);     } })(); 復制代碼

思路很簡單,就是講視圖縮放(Viewport scale)設置為 1/dpr(設備像素比),從而解決 1px border 的問題

注意:此腳本是簡單版,經過對各種品牌、機型進行測試之后發現,此方案基本表現良好,只有對于魅族幾款手機,會存在border過細的問題。原因主要是魅族的手機 dpr 是3,但是屏幕真實分辨率并不高(我個人的理解,并未得到數據上的證實,感興趣的小伙伴可以去驗證),從而視圖縮放過多,導致border過細,解決方式則是通過hack的方式(暫時沒有想到比較好的,有其他方式的小伙伴歡迎評論交流~)

(function () {     // 1px     var dpr = window.devicePixelRatio;     var isIPhone = window.navigator.appVersion.match(/iphone/gi);     var UA = window.navigator.userAgent;     // 對 meizu 某型號進行hack,主要原因是 dpr為3,但是手機屏幕分辨率不夠,會出現 1px border 過細的問題,這種問題主要出現在部分魅族手機上     var hacks = ['m1 note'];     var flag = false;     hacks.forEach(function (item) {         if (UA.indexOf(item) >= 0) {             flag = true;             return;         }     });     if (!isIPhone && flag) {         dpr = dpr >= 2 ? 2 : dpr;     }     var scale = 1 / dpr;     var metaEl = document.querySelector('meta[name="viewport"]') || document.createElement('meta');     metaEl.setAttribute('name', 'viewport');     metaEl.setAttribute('content', 'width=device-width, initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no, viewport-fit=cover');     if (document.documentElement.firstElementChild) {         document.documentElement.firstElementChild.appendChild(metaEl);     } else {         var wrap = document.createElement('div');         wrap.appendChild(metaEl);         document.write(wrap.innerHTML);     } })(); 復制代碼

將上面的腳本放在頁面head中,在開發 1px border 時,可以直接如下:

.border {     border-bottom: 1PX solid #eee; } 復制代碼

注意:如果使用了 postcss-pxtorem 類似插件,需要注意不能將此 1px 單位轉換成 rem,我使用的方法是不需要轉換的 px 使用大寫 PX,這樣 postcss-pxtorem 就不會轉換

三、基礎布局

基礎布局其實涵蓋很多方面,如:

  • 頁面整體布局

  • 文案與icon

    • 各種居中對齊(垂直、水平)

    • 文案與icon對齊(icon應該使用iconfont而不是圖片)

  • z-index 分層

1、頁面整體布局

H5頁面比較常見的布局是頁面分為三部分:head、body、foot,其中head、foot會有吸頂、吸底的效果,常規的使用 fixed布局 會存在些問題,推薦將頁面整體使用flex布局,將head、foot固定,body可滾動,如下:

<div id="page">     <div id="hd">         <!-- head -->     </div>     <div id="bd">         <!-- body -->     </div>     <div id="ft">         <!-- foot -->     </div> </div> 復制代碼
#page {     display: flex;     flex-direction: column;     position: relative;     height: 100%;     overflow: hidden; } #hd {     z-index: 999; } #bd {     flex-grow: 1;     overflow-y: scroll;     -webkit-overflow-scrolling: touch;     &::-webkit-scrollbar {         display: none;     } } 復制代碼

2、文案和icon

使用iconfont

www.iconfont.cn/

注意:iconfont不支持多色icon,所以多色icon可以考慮使用svg或者img

垂直水平居中

實現方案很多:css-tricks.com/centering-c…,建議使用flex布局

文案與icon對齊
<div class="box">     <span>文案與icon垂直居中,水平對齊</span>     <span class="icon-span">         <i class="icons">&#xe625;</i>     </span> </div> 復制代碼
.box {     height: 92px;     font-size: 32px;     line-height: 1;     padding: 0 20px;     display: flex;     align-items: center;     .icon-span {         font-size: 24px;         line-height: 1;         .icons {             color: red;             margin-left: 8px;         }     } } 復制代碼

3、z-index 分層

規范 z-index 的使用,防止因濫用導致在頁面展示問題,分層使用:

$z-layers: (      'below': -1,     'default': 1,     'content': (         'base': 100     ),     'fixed': 990,     'mask': 1000,     'modal': 1020,     'toast': 1040 ); 復制代碼

為了方便使用,使用以下 scss 方法:

$z-layers: (      'below': -1,     'default': 1,     'content': (         'base': 100     ),     'fixed': 990,     'mask': 1000,     'modal': 1020,     'toast': 1040 ); @function map-has-nested-keys($map, $keys...) {     @each $key in $keys {         @if not map-has-key($map, $key) {             @return false;         }         $map: map-get($map, $key);     }     @return true; } @function map-deep-get($map, $keys...) {     @each $key in $keys {         $map: map-get($map, $key);     }     @return $map; } @function z($layers...) {     @if not map-has-nested-keys($z-layers, $layers...) {         @warn "No layer found for `#{inspect($layers...)}` in $z-layers map. Property omitted.";     }     @return map-deep-get($z-layers, $layers...); } 復制代碼

具體使用如下:

.head {     z-index: z('fixed'); } 復制代碼

以上講的布局,可以去 DEMO頁 看看,二維碼:

web移動端布局的那些事兒的圖3

代碼:github.com/HuJiaoHJ/h5…

以上說的方案,我在現在幾款主流的手機上都進行了測試,基本表現良好

寫在最后

本文分享的方案都是我在平時工作中用到的,希望能對有需要的小伙伴有幫助~~~


作者:hujiao
來源:掘金

登錄后免費查看全文
立即登錄
App下載
技術鄰APP
工程師必備
  • 項目客服
  • 培訓客服
  • 平臺客服

TOP