前言
隨著移動端的普及,以及手機尺寸越來越多躬拢,“網(wǎng)頁內(nèi)容自適應(yīng)屏幕尺寸進行顯示的問題” 也日漸凸顯出來躲履,下面講一下常見的適配方案。
本文默認你已經(jīng)對視口聊闯、物理像素工猜、邏輯像素、設(shè)備像素比菱蔬、css像素等移動端基本概念已經(jīng)解篷帅。
1.為何要適配
一般情況下設(shè)計稿的設(shè)計師按照 375 的尺寸設(shè)計,然而汗销,在現(xiàn)在移動終端(就是手機)快速更新的時代犹褒,每個品牌的手機都有著不同的物理分辨率,這樣就會導(dǎo)致弛针,每臺設(shè)備的邏輯分辨率也不盡相同叠骑,此時 375 的設(shè)計稿,如果想要還原那基本是不可能了削茁,因為如果一個左右布局宙枷,左邊如果寫死,右邊自適應(yīng)的話茧跋,每個設(shè)備的右邊所展示的內(nèi)容大小就不盡相同慰丛,這時移動端適配就顯得尤其重要。
2.如何適配
2.1 viewport 配置
<meta name="viewport" content="width=device-width; initial-scale=1; maximum-scale=1; minimum-scale=1; user-scalable=no;">
分別含義如下:
屬性名 | 取值 | 描述 |
---|---|---|
width | device-width或正整數(shù) | 定義視口的寬度瘾杭,單位為像素诅病,一般為device-width:表示寬度為設(shè)備屏幕的寬度 |
height | device-height或正整數(shù) | 定義視口的高度,單位為像素粥烁,一般不用寫 |
initial-scale | [0.0-10.0] | 定義初始縮放值贤笆,一般設(shè)置為1.0 |
minimum-scale | [0.0-10.0] | 定義縮小最小比例,它必須小于或等于maximum-scale設(shè)置 |
maximum-scale | [0.0-10.0] | 定義放大最大比例讨阻,它必須大于或等于minimum-scale設(shè)置 |
user-scalable | yes / no | 定義是否允許用戶手動縮放頁面芥永,默認值 yes |
有幾點注意:
- viewport 標簽只對移動端瀏覽器有效,對 PC 端瀏覽器是無效的
- 當縮放比例為 100% 時钝吮,邏輯像素 = CSS 像素寬度 = 理想視口的寬度 = 布局視口的寬度
- 單獨設(shè)置 initial-scale 或 width 都會有兼容性問題埋涧,所以設(shè)置布局視口為理想視口的最佳方法是同時設(shè)置這兩個屬性
- 即使設(shè)置了 user-scalable = no,在 Android Chrome 瀏覽器中也可以強制啟用手動縮放
2.2 適配方案
2.2.1 基于flexible的rem 適配
- rem的本質(zhì)是等比縮放奇瘦。
- 動態(tài)設(shè)置根元素的font-size來達到我們想要的效果棘催。
- 結(jié)合
postcss-pxtorem
插件將頁面單位轉(zhuǎn)換成rem
設(shè)置 rem 基準值
/*
思路:
1. 頁面初始化的時候設(shè)置一次html的字體大小
2. 監(jiān)聽設(shè)備寬度的改變和頁面刷新,獲取當前屏幕寬度链患,隨之改變html的font-size大小巧鸭。
*/
// 立即執(zhí)行函數(shù)中,傳入window,doucment避免全局污染
(function flexible (window, document) {
// 為獲取HTML文檔的整個文檔元素
var docEl = document.documentElement
//獲取設(shè)備像素比例麻捻,若像素比例為0則以1代替
var dpr = window.devicePixelRatio || 1
// adjust body font size 設(shè)置自適應(yīng)字體大小纲仍,覆蓋html的fontSize
function setBodyFontSize () {
//判斷body是否存在呀袱,存在則設(shè)置大小,不存在則監(jiān)聽DOM加載完后再遞歸調(diào)用此方法
if (document.body) {
document.body.style.fontSize = (12 * dpr) + 'px'
}
else {
document.addEventListener('DOMContentLoaded', setBodyFontSize)
}
}
setBodyFontSize();
// set 1rem = viewWidth / 10
function setRemUnit () {
//獲取屏幕寬度
var rem = docEl.clientWidth / 10
// var rem = 375 / 10
//修改html字體大小
docEl.style.fontSize = rem + 'px'
}
setRemUnit()
// reset rem unit on page resize 監(jiān)聽頁面寬度改變來設(shè)置rem
window.addEventListener('resize', setRemUnit)
window.addEventListener('pageshow', function (e) {
if (e.persisted) {
setRemUnit()
}
})
// detect 0.5px supports 檢測支持0.5px
if (dpr >= 2) {
var fakeBody = document.createElement('body')
var testElement = document.createElement('div')
testElement.style.border = '.5px solid transparent'
fakeBody.appendChild(testElement)
docEl.appendChild(fakeBody)
console.log(testElement.offsetHeight)
if (testElement.offsetHeight === 1) {
docEl.classList.add('hairlines')
}
docEl.removeChild(fakeBody)
}
}(window, document))
核心代碼解釋:
// set 1rem = 邏輯像素(設(shè)備獨立像素) / 10
function setRemUnit () {
var rem = docEl.clientWidth / 10
// 375/10 = 37.5
docEl.style.fontSize = rem + 'px'
}
setRemUnit()
將html節(jié)點的font-size設(shè)置為頁面clientWidth(布局視口)的1/10郑叠,即:1rem = 布局視口的1/10夜赵,
在iphone6下:docEl.clientWidth=設(shè)備獨立像素(邏輯像素)= 布局視口寬度 = 理想窗口寬度 = 375。此時:1rem = 375/10 +px = 37.5px
postcss-pxtorem將單位轉(zhuǎn)化為 rem
module.exports = {
plugins: {
'autoprefixer': {
browsers: ['Android >= 4.0', 'iOS >= 7']
},
'postcss-pxtorem': {
rootValue: 37.5,
propList: ['*', '!font-size'],
selectorBlackList: ['van-circle__layer', 'ignore'],
}
}
}
- rootValue 是轉(zhuǎn)換px的基準值乡革,參考設(shè)備iPhone6寇僧,設(shè)備寬度375px。
規(guī)則:基準值=當前設(shè)備寬度的1/10 - 基準值設(shè)置代碼中沸版,在iPhone6設(shè)備設(shè)置的 html—>font-size 也為37.5px
- 但是設(shè)計稿尺寸750px大小嘁傀,所以在設(shè)計稿量取的尺寸使用時候需要除以2 。
因為當年 viewport 在低版本安卓設(shè)備上還有兼容問題视粮,而 vw细办,vh 還沒能實現(xiàn)所有瀏覽器兼容,所以 flexible 方案用 rem 來模擬 vmin 來實現(xiàn)在不同設(shè)備等比縮放的“過度”方案蕾殴,建議大家使用vw來替代此方案笑撞。
2.2.2 vw,vh 適配
vh钓觉、vw 方案即將視覺視口寬度 window.innerWidth 和視覺視口高度 window.innerHeight 等分為 100 份茴肥。
vh 和 vw 方案和 rem 類似也是相當麻煩需要做單位轉(zhuǎn)化,而且 px 轉(zhuǎn)換成 vw 不一定能完全整除荡灾,因此有一定的像素差瓤狐。
不過在工程化的今天,webpack 解析 css 的時候用 postcss-loader 有個 postcss-px-to-viewport 能自動實現(xiàn) px 到 vw 的轉(zhuǎn)化批幌。
{
loader: 'postcss-loader',
options: {
plugins: ()=>[
require('autoprefixer')({
browsers: ['last 5 versions']
}),
require('postcss-px-to-viewport')({
viewportWidth: 375, //視口寬度(數(shù)字)
viewportHeight: 1334, //視口高度(數(shù)字)
unitPrecision: 3, //設(shè)置的保留小數(shù)位數(shù)(數(shù)字)
viewportUnit: 'vw', //設(shè)置要轉(zhuǎn)換的單位(字符串)
selectorBlackList: ['.ignore', '.hairlines'], //不需要進行轉(zhuǎn)換的類名(數(shù)組)
minPixelValue: 1, //設(shè)置要替換的最小像素值(數(shù)字)
mediaQuery: false//允許在媒體查詢中轉(zhuǎn)換px(true/false)
})
]
}