web移動端佈局的那些事兒

原文地址:github.com/HuJiaoHJ/bl…css

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

  • 移動端適配
  • 1px border
  • 基礎佈局

本文主要分享這三個話題vue

1、移動端適配

提起移動端適配,你們想到的確定是remflexible.js,本文要分享的方案是 vw + remhtml5

對移動端適配不熟悉的同窗,能夠看看:git

vw 是什麼?

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

  • vw:Viewport's Width 簡寫,1vw 等於 window.innerWidth 的 1%
  • vh:Viewport's Height 簡寫,1vh 等於 window.innerHeight 的 1%
  • vmin:當前 vw 和 vh 中較小值
  • vmax:當前 vw 和 vh 中較大值

常規的 rem 的適配方案(包括flexible),其實就是經過 js 動態計算,模擬 vw 的效果,過去使用這種方案主要緣由是 vw 存在必定的兼容問題,不過對於如今而言,vw 也基本能知足對兼容性的要求web

能夠看到,Android 4.4 以上及 IOS 8.0 以上均已支持,因此如今咱們能夠直接使用 vw 來作移動端適配啦app

vw + rem 方案

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

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

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

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

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 中便可

2、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 就不會轉換

3、基礎佈局

基礎佈局其實涵蓋不少方面,如:

  • 頁面總體佈局
  • 文案與icon
    • 各類居中對齊(垂直、水平)
    • 文案與icon對齊(icon應該使用iconfont而不是圖片)
  • z-index 分層

一、頁面總體佈局

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;
    }
}
複製代碼

二、文案和icon

使用iconfont

www.iconfont.cn/

注意:iconfont不支持多色icon,因此多色icon能夠考慮使用svg或者img

垂直水平居中

實現方案不少:css-tricks.com/centering-c…

文案與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;
        }
    }
}
複製代碼

三、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頁看看,二維碼:

代碼:github.com/HuJiaoHJ/h5…

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

寫在最後

本文分享的方案都是我在平時工做中用到的,但願能對有須要的小夥伴有幫助~~~

喜歡個人文章小夥伴能夠去 個人我的博客 點star ⭐️

相關文章
相關標籤/搜索