社區(qū)精選|談?wù)?H5 移動端適配原理
今天小編為大家?guī)淼氖巧鐓^(qū)作者 熊的貓 的文章,讓我們一起來學(xué)習(xí) H5 移動端適配原理。
H5 移動端 開發(fā)的必不可少的一個環(huán)節(jié)就是 移動端網(wǎng)頁的適配,因為 UI 通常只會提供 大小固定的設(shè)計稿,而各種不同移動設(shè)備具有不同的頁面分辨率和大小,所以適配的目的就是讓一份設(shè)計稿在不同移動設(shè)備上表現(xiàn)出一致性。
雖然現(xiàn)如今各種插件都可以幫助我們快速配置完成,例如 lib-flexible、postcss-pxtorem、postcss-px-to-viewport 等等,但不少小伙伴在被問及相關(guān)原理時卻很難說清楚,那么本篇文章我們就一起來探究一下其中原理吧!!!
文中有不當(dāng)之處,歡迎在評論區(qū)指正
CSS 中的尺寸單位
px 像素單位
px 全稱為 pixel(像素),它是相對于 屏幕顯示器分辨率(桌面設(shè)定的分辨率,不是顯示器的物理分辨率) 而言的,在 相同/不同 的設(shè)備上 1px 表示多個 設(shè)備像素。
em 相對單位


rem (root em) 相對單位
-
rem 相對于 html 根元素的,因此在 body 標(biāo)簽里面設(shè)置 font-size 是不起作用的 -
因此 rem 就可做到 目標(biāo)元素 與 根元素 間保持 成比例 的大小關(guān)系,又可以避免字體大小逐層復(fù)合的連鎖反應(yīng)等,例如公共的字體大小可以在 body 中設(shè)置即可

vw 和 vh
-
vw 全稱是 viewport width,代表的是 視口的寬度,相對于 視口 viewport 的 寬度 -
vh 全稱是 viewport height,代表的是 視口的高度,相對于 視口 viewport 的 高度 -
vw 和 vh 是將 視口 寬/高 都分成 100 份,因此 100vw = 視口寬、100vh = 視口高
-
vmin 和 vmax 代表的是 視口寬度 和 視口高度 中的 最小值 和 最大值 -
vmin = 視口高度 vh 和 寬度 vw 間的最小值 -
vmax = 視口高度 vh 和 寬度 vw 間的最大值

適配方案
核心原理
將 設(shè)備視口 劃分成 n 份, n 可以是 任何正確的值(如 flexible.js 中的 n = 10)
設(shè)置 設(shè)備視口 根元素 html 的 font-size = 設(shè)備視口寬 ÷ 份數(shù) n,即得到 設(shè)備視口 1 rem 到底表示 多少設(shè)備視口 px
將 設(shè)計稿 也同樣劃分成 n 份,此時 設(shè)計稿中的 a px 對應(yīng) 設(shè)備視口 b rem 的計算方式為
設(shè)備視口 b rem = 設(shè)計稿 a px ÷ (設(shè)計稿 寬 ÷ n 份)
舉個例子
設(shè)備視口寬為 375px

(function (n = 10){
const dEl = document.documentElement;
function setRem(){
const rem = dEl.clientWidth / n;
dEl.style.fontSize = rem + 'px';
}
// 初始化執(zhí)行
setRem()
// 視口大小變動時執(zhí)行
window.onresize = setRem
})()
設(shè)計稿寬為 750px

-
將 設(shè)計稿 也分成 10 份,每份大小 = 750 ÷ 10 = 75 px -
此時 設(shè)計稿 上的 "點我拍照"(font-size: 34px) 的文案轉(zhuǎn)換成符合 設(shè)備視口 對應(yīng)的 rem 就為:

設(shè)備視口 中 文字 font-size = 34 ÷ 75 = 0.4533333333333333 rem ≈ 0.45 rem
【注意】 一般計算結(jié)果(人為計算、插件自動化自動化計算)都不會使用這么長的小數(shù)位,比如 0.4533333333333333 rem ≈ 0.45 rem,此時:
原始值 0.4533333333333333 rem = 0.4533333333333333 * 37.5 = 17 px 保留兩位小數(shù)后的值 0.45 rem = 0.45 * 37.5 = 16.875 px 而在肉眼觀察下 16.875 px 和 17 px 是沒有差別的,因此可以忽略不計
用 amfe-flexible 和 postcss-pxtorem 驗證




-
34px 轉(zhuǎn)換成 rem = 34 ÷ 75,這種不直觀的計算叫 復(fù)雜計算,若可以實現(xiàn) 34 ÷ 100 即可得到相應(yīng)的 rem 的方式,就稱為 簡單計算(任何數(shù)除以 10 或 100 都很容易口算)
vw/vh 適配
-
rem 的適配方式支持自定義將設(shè)備視口劃分為 n 份,n 可以是任何正確值 -
vw/vh 就是將設(shè)備視口劃分為 100 份,不支持自定義
CSS 預(yù)處理器 — 簡化計算
// plugin.js
module.exports = {
install: function (less, pluginManager, functions) {
functions.add('px2vw', (param, perVW) => {
if (!param.value) return '0vw'
if (!perVW.value) return param.value + 'px'
return Number(param.value) / perVW.value + 'vw'
})
},
}
// 具體使用
<style lang="less">
@plugin './plugin.js';
@design-width: 750;
@per-vw: @design-width / 100;
.text {
font-size: px2vw(34, @per-vw);
color: #457fff;
}
</style>
<style lang="scss">
$design-width: 750;
$per-vw: $design-width / 100;
@function px2vw($param) {
@return $param / $per-vw + 'px';
}
.text {
font-size: px2vw(34);
color: #457fff;
}
</style>
使用 postcss-px-to-viewport 進行驗證
文本和原始樣式
postcss-px-to-viewport 配置

等比縮放 — viewport <meta> 標(biāo)記
很明顯,我們只需要控制其中的 width 和 initial-scale 的值即可,它們分別是代表當(dāng)前設(shè)備視口寬度和縮放比的值。
(function (designWidth) {
const dEl = document.documentElement;
let meta = document.querySelector("meta[name=viewport]");
// 頁面中不存在 <meta name="viewport" /> 時,手動創(chuàng)建一個
if(!meta) {
meta = document.createElement('meta');
meta.setAttribute('name', 'viewport');
document.head.appendChild(meta);
}
function setMetaContent(){
const deviceWidth = dEl.clientWidth;
const scale = deviceWidth / designWidth;
const content = `width=${deviceWidth}, initial-scale=${scale}`;
meta.setAttribute("content", content);
}
setMetaContent();
window.addEventListener("resize", setMetaContent)
})(750);

第三方組件庫如何做適配?
-
Viewport 布局 -
Vant 默認(rèn)使用 px作為樣式單位,如果需要使用viewport單位 (vw, vh, vmin, vmax),推薦使用 postcss-px-to-viewport 進行轉(zhuǎn)換 -
Rem 布局適配 -
postcss-pxtorem 是一款 PostCSS 插件,用于將 px 單位轉(zhuǎn)化為 rem 單位 -
lib-flexible 用于設(shè)置 rem 基準(zhǔn)值 -
桌面端適配 -
若需要在桌面端使用 Vant,可以引入 @vant/touch-emulator,這個庫會在桌面端自動將 mouse事件轉(zhuǎn)換成對應(yīng)的touch事件,使得組件能夠在桌面端使用
vant-ui:https://vant-ui.github.io/vant/#/zh-CN/advanced-usage
postcss-px-to-viewport :https://github.com/evrone/postcss-px-to-viewport
postcss-pxtorem:https://github.com/cuth/postcss-pxtorem
lib-flexible:https://github.com/amfe/lib-flexible
@vant/touch-emulator:https://github.com/vant-ui/vant/tree/main/packages/vant-touch-emulator
最后
往期推薦
社區(qū)精選|納尼!CSS 也能實現(xiàn)碰撞檢測?
社區(qū)精選|記一次 Vue-CLI 生產(chǎn)項目的打包優(yōu)化
社區(qū)精選|TypeScript 玩轉(zhuǎn)類型操作

