移動(dòng)端常見適配方案
做移動(dòng)端頁面有一段時(shí)間了,總結(jié)下工作中常用的幾種移動(dòng)端適配方案。
基礎(chǔ)
網(wǎng)上已經(jīng)有非常多的基礎(chǔ)知識(shí)總結(jié),其中容易搞混的概念是視口。
meta 標(biāo)簽中的 viewport 屬性,就是 視圖 的含義
視口分為
- 布局視口
- 視覺視口
- 理想視口
布局視口
也就是 <meta name="viewport" content="width=device-width"> 中 width 屬性的含義
我們在css中寫的所有樣式,就是相對于 布局視口 進(jìn)行布局的
默認(rèn)情況下,移動(dòng)端的布局視口并不是屏幕寬度,而是一般在768px ~ 1024px間(大部分情況下980px)
可以通過 document.documentElement.clientWidth 獲取 (根據(jù) width 和 initial-scale 來確定)
視覺視口
視覺視口是指用戶通過設(shè)備屏幕看到的區(qū)域,默認(rèn)等于當(dāng)前瀏覽器的窗口大小(當(dāng) initial-scale 為1)
當(dāng)用戶對瀏覽器進(jìn)行縮放時(shí),不會(huì)改變布局視口的大小,所以頁面布局是不變的,但是 縮放會(huì)改變覺視口的大小
可以通過 window.innerWidth 獲取 (會(huì)隨著縮放進(jìn)行改變)
放大頁面,此時(shí) window.innerWidth 反而減小 (頁面放大,你看到的東西也變少了)
理想視口
理想視口是指網(wǎng)站在移動(dòng)設(shè)備中的理想大小,這個(gè)大小就是設(shè)備的屏幕大小
也就是 <meta name="viewport" content="width=device-width"> 中 device-width 的含義
可以通過 screen.width 獲取 (常量,不會(huì)改變)
initial-scale
<meta name="viewport" content="width=device-width, initial-scale=0.5">
根據(jù)公式 initial-scale = 理想視口寬度 / 視覺視口寬度
假設(shè)理想視口寬度為 414px (device-width),此時(shí)設(shè)置 initial-scale 為0.5,那么視覺視口寬度就是 414 / 0.5 = 818
如果這時(shí)你獲取 document.documentElement.clientWidth (布局視口)的值,會(huì)發(fā)現(xiàn)不是 414px 而是 818px
結(jié)論: 布局視口寬度取的是width和視覺視口寬度的最大值
思考題:
<meta name="viewport" content="width=600, initial-scale=2">
假設(shè)理想視口寬度為 414px (device-width),此時(shí) document.documentElement.clientWidth (布局視口)的值是多少?
總結(jié)
- document.documentElement.clientWidth : 布局視口,css中一般寫成 width=device-width
- window.innerWidth : 視覺視口,頁面縮放都會(huì)實(shí)時(shí)改變該值
- screen.width : 理想視口,頁面屏幕大小(設(shè)備獨(dú)立像素),也就是css中的 device-width
常見適配方案
簡單一句話概括:移動(dòng)端適配就是在進(jìn)行 屏幕寬度 的 等比例縮放 :
平時(shí)我們開發(fā)中,拿到的移動(dòng)端設(shè)計(jì)稿一般是 750 * 1334 尺寸大小( iPhone6 的設(shè)備像素為標(biāo)準(zhǔn)的設(shè)計(jì)圖)。那如果在 750px 設(shè)計(jì)稿上量出的元素寬度為 100px ,那么在 375px 寬度的屏幕下,這個(gè)元素寬度就應(yīng)該等比例縮放成 50px 。
所以適配的難點(diǎn)是:如果實(shí)現(xiàn)頁面的等比例縮放?
Rem 方案
該方案的核心就是:所有需要?jiǎng)討B(tài)布局的元素,不再使用 px 固定尺寸,而是采用 rem 相對尺寸
rem 的大小是相對于根元素 html 的字體大?。喝绻?span> html 的 font-size 為100px,那么 1rem 就等于100px
現(xiàn)在我們假定:
750px 屏幕下 html 的 font-size 為100px,也就是 1rem 為100px,那么 200px 寬度的 .box 元素,就應(yīng)該寫成 2rem
那么現(xiàn)在:
375px 屏幕下,我們需要 .box 元素渲染成 100px
由于 .box 的寬度仍然是 2rem ,因此,這時(shí)候我們就需要 1rem 為50px,也就是說,此時(shí) html 的 font-size 為50px
于是此時(shí),我們可以得出一個(gè)公式:
(750) / (100) = (當(dāng)前屏幕尺寸) / (當(dāng)前屏幕1rem)
把這個(gè)公式進(jìn)行一次數(shù)學(xué)轉(zhuǎn)換就能得到:
(當(dāng)前屏幕1rem) = 100 * (當(dāng)前屏幕尺寸) / 750
翻譯成js語言就是
將代碼優(yōu)化一下
考慮到Andorid端字體渲染的問題以及頁面大小變化的監(jiān)聽,最終的代碼如下:
注意的是:我們?nèi)?span> 100px 作為設(shè)計(jì)稿的1rem,是因?yàn)榉奖阌?jì)算,比如設(shè)計(jì)稿上量出 250px ,我們就可以很容易的計(jì)算出為 2.5rem 。
我們當(dāng)然也可以把 50px 作為設(shè)計(jì)稿的1rem,這時(shí)設(shè)計(jì)稿上的 250px ,就要寫成 5rem 。
其實(shí)我們也可以借助于postcss-pxtorem或者 SCSS 函數(shù)來幫我們自動(dòng)轉(zhuǎn)換單位
通過Rem方案,需要?jiǎng)討B(tài)縮放的元素,我們使用 rem 相對單位,不需要縮放的元素,我們?nèi)匀豢梢允褂?span> px 固定單位。
不過在大屏設(shè)備下(例如ipad或者pc端),由于我們的頁面是等比例縮放,這時(shí)候頁面的元素會(huì)被放大很多(屏幕寬度大,導(dǎo)致根元素字體1rem也變大)。但是在大屏下,我們真正希望的是用戶看到更多的內(nèi)容,這時(shí)候我們可以使用媒體查詢的方式來限制根元素的字體,從而防止在大屏下元素過大的問題。
或者修改js腳本的邏輯
VW 方案
vw 是相對單位,1vw 表示屏幕寬度的 1%
其實(shí)我們的 REM方案 就是 VW方案 的模擬,之前我們有一個(gè)公式:
(750) / (100) = (當(dāng)前屏幕尺寸) / (當(dāng)前屏幕1rem)
換一個(gè)轉(zhuǎn)換方式:
(當(dāng)前屏幕1rem) = (當(dāng)前屏幕尺寸) / 7.5
而 vw 單位其實(shí)就是:
(當(dāng)前屏幕1vw) = (當(dāng)前屏幕尺寸) / 100
因此, REM方案 就是用 JS 把屏幕寬度分成了7.5份,而 CSS3 中新增的 vw 單位,原生實(shí)現(xiàn)了把屏幕寬度分成了100份
所以,在 VW方案 中,我們不再需要使用JS腳本了!
750px 設(shè)計(jì)稿中, 1vw 等于 7.5px (750 / 100),因此,在設(shè)計(jì)稿中,量出 200px 的寬度,就因?yàn)閷懗?span> 26.667vw (200 / 7.5)
不過使用 vw 換算,并不像 rem 那么方便,這時(shí)候我們可以借助 postcss-px-to-viewport 或者 SCSS 函數(shù)來幫我們自動(dòng)轉(zhuǎn)換單位
同樣,在大屏設(shè)備下,由于屏幕寬度大,所以頁面的元素同樣會(huì)放大很多(屏幕寬度大,1vw也很大)。但是由于 vw 是相對屏幕寬度的,所以我們不能像 REM方案 中一樣,手動(dòng)控制 html 的根字體大小,這也是使用 VW方案 的一個(gè)缺點(diǎn)。
REM + VW 方案
REM方案 的優(yōu)勢是可以手動(dòng)控制 rem 的大小,防止屏幕太大時(shí),頁面元素也縮放很大,但是缺點(diǎn)就是需要使用 JS 。 VW方案 剛好相反,無需使用 JS 但是無法手動(dòng)控制 vw 的大小。
其實(shí)我們可以把兩者結(jié)合:
對于布局元素,我們?nèi)匀皇褂?span> rem 單位。但是對于根元素的字體大小,我們不需要使用JS來動(dòng)態(tài)計(jì)算了
這段js可以直接使用css來實(shí)現(xiàn)
對于大屏設(shè)備,我們使用媒體查詢
更詳細(xì)的 vw+rem布局方案 可以見 《基于vw等viewport視區(qū)單位配合rem響應(yīng)式排版和布局》
viewport 縮放方案
還有一種更簡單粗暴的方法,就是我們設(shè)置 initial-scale
我們的布局完全基于設(shè)計(jì)稿 750px ,布局元素單位也使用 px 固定單位 (布局視口寫死750px)
對于 375px 寬度,我們就將整個(gè)頁面縮放 0.5 :
<meta name="viewport" content="width=750, initial-scale=0.5, minimum-scale=0.5, maximum-scale=0.5, user-scalable=0">
此方案的缺點(diǎn): 整個(gè)頁面都被縮放了,對于不想縮放的元素?zé)o法控制。
市面上一些營銷H5頁面,由于是通過后臺(tái)可視化拖拽搭建出來的,為了適配各種尺寸的屏幕,該方案是成本最低的實(shí)現(xiàn)(易企秀就是使用這種方案)
實(shí)戰(zhàn)
我們拿線上B站的會(huì)員購作為示例
- rem方案
- vw方案
- rem+vw方案
- viewport方案
請使用chrome開發(fā)者工具模擬移動(dòng)端設(shè)備查看
源碼直接右鍵查看即可,代碼沒有經(jīng)過壓縮,可以很直觀的看到各種方案的css適配寫法