前言
歡迎關注同名公眾號《熊的貓》,文章會同步更新,也可快速加入前端交流羣!
H5 移動端 開發的必不可少的一個環節就是 移動端網頁的適配,因為 UI 通常只會提供 大小固定的設計稿,而各種不同移動設備具有不同的頁面分辨率和大小,所以適配的目的就是讓一份設計稿在不同移動設備上表現出一致性。
雖然現如今各種插件都可以幫助我們快速配置完成,例如 lib-flexible、postcss-pxtorem、postcss-px-to-viewport 等等,但不少小夥伴在被問及相關原理時卻很難説清楚,那麼本篇文章我們就一起來探究一下其中原理吧!!!
文中有不當之處,歡迎在評論區指正!!!
CSS 中的尺寸單位
在瞭解具體的適配方案之前,我們先把 CSS 中適配會涉及到的相關尺寸單位進行一個瞭解吧,總結起來就是一句話:CSS 中的尺寸單位都是 相對長度單位,只是相對的目標不同。
px 像素單位
px 全稱為 pixel(像素),它是相對於 屏幕顯示器分辨率(桌面設定的分辨率,不是顯示器的物理分辨率) 而言的,在 相同/不同 的設備上 1px 表示多個 設備像素。
當 一個像素點越大 時, 呈現的圖像就會 越模糊;當一個像素點越小時, 像素點就會 越密集, 呈現的圖像就會 越清晰。
![image.png]()
em 相對單位
好多人都認為 em 就是相對於 父元素 font-size,實際上在不同的 CSS 屬性當中使用 em 其相對的目標也是不同,如下:
-
用於 font-size 中則是相對於 父元素 font-size 大小
-
用於 其他屬性(如 width,height) 中使用是相對於 自身 font-size 大小
值得注意的是,若 當前元素/父元素 的 font-size 未設置,由於 font-size 屬性值可被繼承的原因,可逐級向上查找,最終找不到則相對於瀏覽器默認字體大小,即 font-size = 16px。
rem (root em) 相對單位
rem 是 CSS3 新增的一個相對單位,它只相對於 根元素 html 的 font-size 字體大小,rem 與 em 的區別在於:
rem相對於html根元素的,因此在body標籤裏面設置font-size是不起作用的- 因此
rem就可做到 目標元素 與 根元素 間保持 成比例 的大小關係,又可以避免字體大小逐層複合的連鎖反應等,例如公共的字體大小可以在body中設置即可

!
vw 和 vh
vw 全稱是 viewport width,代表的是 視口的寬度,相對於 視口 viewport 的 寬度
vh 全稱是 viewport height,代表的是 視口的高度,相對於 視口 viewport 的 高度
vw 和 vh 是將 視口 寬/高 都分成 100 份,因此 100vw = 視口寬、100vh = 視口高
與之相關的還有vmin和vmax兩個單位
- vmin 和 vmax 代表的是 視口寬度 和 視口高度 中的 最小值 和 最大值
vmin= 視口高度vh和 寬度vw間的最小值vmax= 視口高度vh和 寬度vw間的最大值
適配方案
rem 適配(等比適配)
核心原理
-
將 設備視口 劃分成 n 份, n 可以是 任何正確的值(如
flexible.js中的n = 10)- 設置 設備視口
根元素 html的font-size = 設備視口寬 ÷ 份數 n,即得到 設備視口1rem 到底表示 多少設備視口 px
- 設置 設備視口
-
將 設計稿 也同樣劃分成 n 份,此時 設計稿中的
apx 對應 設備視口brem 的計算方式為- 設備視口
brem = 設計稿apx ÷ (設計稿寬÷n份)
- 設備視口
舉個例子
設備視口寬為 375px
-
將設備視口分成 10 份,設置
根元素 html 的 font-size=375÷10=37.5px,即1rem =37.5px(function (n = 10){ const dEl = document.documentElement; function setRem(){ const rem = dEl.clientWidth / n; dEl.style.fontSize = rem + 'px'; } // 初始化執行 setRem() // 視口大小變動時執行 window.onresize = setRem })()
設計稿寬為 750px
- 將 設計稿 也分成 10 份,每份大小 =
750÷10=75px -
此時
設計稿上的"點我拍照"(font-size: 34px)的文案轉換成符合設備視口對應的rem就為:- 設備視口 中
文字 font-size=34 ÷ 75=0.4533333333333333rem ≈0.45rem
- 設備視口 中
【
注意】 一般計算結果(人為計算、插件自動化自動化計算)都不會使用這麼長的小數位,比如0.4533333333333333rem ≈0.45rem,此時:
- 原始值
0.4533333333333333rem =0.4533333333333333*37.5=17px- 保留兩位小數後的值
0.45rem =0.45*37.5=16.875px而在肉眼觀察下
16.875px 和17px 是沒有差別的,因此可以忽略不計
用 amfe-flexible 和 postcss-pxtorem 驗證
-
文本和原始樣式
-
amfe-flexible和postcss-pxtorem配置 -
最終展示效果
早期 rem 適配優化(過期方案,瞭解即可)
在早期還沒有各種 CSS 預處理器 和 自動化計算的插件 時(即 還需要人為計算時),上述 rem 適配的方案 有一個缺點,那就是針對 設計稿中不同的 px 的轉換為 設備視口 rem 的計算過程還是比較繁瑣,特別是一些比較難算的數值。
例如,上述將 設計稿 34px 轉換為 設備視口 0.9rem 的例子,對大部分人來説是不能 直接/快速 看到設計稿中 px 的數值就能直接算出其對應的 rem 單位的數值的,因此需要進行優化。
而 優化 的核心就是 將 複雜計算 變成 簡單計算,例如在 寬 750 px 的設計稿中:
34px轉換成 rem =34÷75,這種不直觀的計算叫 複雜計算,若可以實現34÷100即可得到相應的 rem 的方式,就稱為 簡單計算(任何數除以 10 或 100 都很容易口算)
也就是説,如果我們希望所有設計稿上 px 的計算都是 簡單計算,那麼我們就需要保證其 渲染結果 是正確的即可,換句話説,就是我們需要調整設備視口的 1 rem = n px 中 n 的值讓其能夠滿足 34 ÷ 100 = 0.34 rem 的情況下還能夠被正常渲染為 17 px 即可,這無非就涉及到一個數學倍數計算而已,就不過多展開了。
vw/vh 適配
前面説過,vw 和 vh 是將 視口 寬/高 都分成 100 份,相對於 設備視口 375px 來説 1vw = 375 ÷ 100 = 3.75px。
經過了 rem 適配方案 的介紹,vw/vh 這種適配方式就是相當於把替換了原本的 rem 單位,因此,這個方式的計算方式和 rem 的方式 如出一轍,區別就在於:
rem的適配方式支持自定義將設備視口劃分為n份,n可以是任何正確值vw/vh就是將設備視口劃分為100份,不支持自定義
因此,假設將 設計稿 750px 中的 34px 轉換為 設備視口 n vw 就等於 n = 34 ÷ 7.5 = 4.533333333333333 vw ≈ 4.53 vw。
CSS 預處理器 — 簡化計算
如果使用的是 CSS 預處理器(Less、Sass),那麼就可以通過定義一個全局的 函數 來幫助我們進行運算,例如:
-
Less 中 px2vw() 的定義:
// 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> -
Sass 中 px2vw() 的定義:
<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> 標記
所謂 等比縮放 也就是我們不需要關注 設計稿 px 到底對應多少 設備視口 rem 或 vw,在開發時,直接使用 設計稿提供的數據 px 即可,然後在將整體頁面按照 設備視口 / 設計稿 的比例進行 整體縮放。
而縮放就需要使用到 使用 "viewport" <meta> 標記 來控制視口的大小和形狀了,例如常見的 <meta> 標記如下:
很明顯,我們只需要控制其中的 width 和 initial-scale 的值即可,它們分別是代表當前設備視口寬度和縮放比的值。
還是用 設計稿 750px 和 設備視口 375px 舉例子,因為我們是直接只用設計稿提供的數據來開發,那麼上面的 width = 設備視口寬、initial-scale = 設備視口 / 設計稿。
(function (designWidth) {
const dEl = document.documentElement;
let meta = document.querySelector("meta[name=viewport]");
// 頁面中不存在 <meta name="viewport" /> 時,手動創建一個
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);
第三方組件庫如何做適配?
不知道你是不是會有一些疑問,比如第三方組件庫的適配方式和我們使用的不一致怎麼辦?
不用擔心,第三方組件庫默認都是直接使用 px 的方式來開發的,因此我們在項目中定義的適配方式就是第三方組件庫的適配方式,不會產生衝突的。
例如,vant-ui 文檔中很貼心的為你列出了 瀏覽器適配方案(詳情可見文檔):
-
Viewport 佈局
- Vant 默認使用
px作為樣式單位,如果需要使用viewport單位 (vw, vh, vmin, vmax),推薦使用 postcss-px-to-viewport 進行轉換
- Vant 默認使用
-
Rem 佈局適配
- postcss-pxtorem 是一款 PostCSS 插件,用於將 px 單位轉化為 rem 單位
- lib-flexible 用於設置 rem 基準值
-
桌面端適配
- 若需要在桌面端使用 Vant,可以引入 @vant/touch-emulator,這個庫會在桌面端自動將
mouse事件轉換成對應的touch事件,使得組件能夠在桌面端使用
- 若需要在桌面端使用 Vant,可以引入 @vant/touch-emulator,這個庫會在桌面端自動將
最後
歡迎關注同名公眾號《熊的貓》,文章會同步更新,也可快速加入前端交流羣!
以上就是移動端適配的幾種方式的原理了,知道了這些內容之後,其實就不難發現常用的適配插件不過是幫助我們實現了上述的內容和一些細節,例如 自動計算、自動轉換、判斷機型 等等。
希望本文對你有所幫助!!!