web移動端佈局範疇很廣,其中比較基礎的幾個話題:
- 移動端適配
- 1px border
- 基礎佈局
本文主要分享這三個話題
一、移動端適配
提起移動端適配,大家想到的肯定是rem
、flexible.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 中較大值
常規的 rem 的適配方案(包括flexible),其實就是通過 js 動態計算,模擬 vw 的效果,過去使用這種方案主要原因是 vw 存在一定的相容問題,不過對於現在而言,vw 也基本能滿足對相容性的要求
可以看到,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
注意:iconfont不支援多色icon,所以多色icon可以考慮使用svg或者img
垂直水平居中
實現方案很多:css-tricks.com/centering-c…
文案與icon對齊
<div class="box">
<span>文案與icon垂直居中,水平對齊</span>
<span class="icon-span">
<i class="icons"></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頁看看,二維碼:
以上說的方案,我在現在幾款主流的手機上都進行了測試,基本表現良好
寫在最後
本文分享的方案都是我在平時工作中用到的,希望能對有需要的小夥伴有幫助~~~
喜歡我的文章小夥伴可以去 我的個人部落格 點star ⭐️