作者:子非魚
轉發鏈接:https://mp.weixin.qq.com/s/uQ8c2Z6GJr4eyH3kidZt3g
前言
隨著Web技術的革新,移動端適配方案也在不斷的變化,網上有很多關于移動端適配的文章,說什么rem布局已經過時,vm適配才是最好的適配方案。有這種理解的同學是錯誤的,任何適配方案都有它的優缺點,要結合自己的使用場景來進行選擇。
前面小編也發布了幾篇關于移動適配的文章,一起來復習一下:
《手把手教你繞過移動端適配大坑》
《吃透移動端 1px|從基本原理到開源解決方案》
《吃透移動端 H5 與 Hybrid|實踐踩坑12種問題匯總》
文章先講一下幾種常見的適配方案,然后再看看幾個大廠(騰訊、京東、網易、小紅書、微博、美團、B站、搜狐、餓了么、攜程、大眾點評、知乎、拍拍貸、陸金所)的移動端頁面都采用了什么樣的適配方案,最后討論下各個適配方法的適用場景和優缺點,如果有不對之處,希望能得到大佬們的指正。
移動端適配的重新思考
1
移動端適配就是用rem或vw ?
并不是所有場景都適合用用rem或vw進行適配。
- vw和rem適配的本質是等比例縮放,讓頁面在不同屏幕尺寸下有類似于矢量圖片縮放的效果,保證了頁面元素之間的尺寸縮放比例和位置。
- 這兩種適配方案適合視覺組件種類比較多,視覺設計對元素位置的相對關系依賴較強的移動端頁面,基本上大部分頁面都可以用這兩種方案進行適配。
- 但對于文本內容較多,我們希望引導用戶沉浸在更多的內容而不是更大的內容的,這種等比例縮放的方案并不能滿足要求,我推薦直接使用px結合flex等布局方式進行適配。
2
rem該拋棄了,使用vw不香么 ?
vm適配不是萬能的,最好與rem配合使用
- 當初之所以使用rem的方案流行開來正是因為在那時viewport units的瀏覽器支持程度不甚理想(IOS 8+, Android 4.4+ 參見viewport units的caniuse)。而相比較之下rem就好多了(IOS 4.1+, Android 2.1+ 參見caniuse),所以對于vw,在當時的大環境下前端想說愛你不容易。
- 隨著前端技術的革新,最主要是各大瀏覽器廠商的給力,除Opera Mini全版本和IE低版本不支持之外,其他的瀏覽器基本上都已經支持vw了,開始有人或者有團隊在探討論在實際項目中的使用。雖然大漠老師在《再聊移動端頁面的適配》一文中提出的vw方案中使用viewport-units-buggyfill庫進行兼容的做法,我個人更是不建議,由于這個庫使用了css content屬性進行兼容處理,官方文檔中就指出了對部分瀏覽器的img標簽有影響 ,需要全局引入一條css規則。且對于需要正常使用content的情況(如:圖標字體)也會引起不可避免的沖突,另外也不支持偽元素的兼容。所以從我個人的角度來說,如果你一定要問我使用怎樣的vw適配方案,我會推薦給你上述兩種vw + rem的方案。
- 雖然采用vw適配后的頁面效果很好,但是它是利用視口單位實現的布局,依賴視口大小而自動縮放,無論視口過大還是過小,它也隨著視口過大或者過小,失去了最大最小寬度的限制。
移動端適配方案
1
rem適配
rem適配的本質是布局等比例的縮放,通過動態設置html的font-size來改變rem的大小。
viewport 配置
1<!-- dpr = 1-->
2<meta name="viewport" content="width=device-width; initial-scale=1; maximum-scale=1; minimum-scale=1; user-scalable=no;">
上面把scale設置成固定1倍的視口的大小,也可以根據dpr的值縮放viewport,如下:
1//下面是根據設備dpr設置viewport
2var dpr = window.devicePixelRatio || 1
3var scale = 1 / dpr
4
5viewport.setAttribute(
6 "content",
7 "width=device-width" +
8 ",initial-scale=" +
9 scale +
10 ", maximum-scale=" +
11 scale +
12 ", minimum-scale=" +
13 scale +
14 ", user-scalable=no"
15)
有幾點要注意
- viewport標簽只對移動端瀏覽器有效,對PC端瀏覽器是無效的。
- 當縮放比例為100%時,邏輯像素 = CSS 像素寬度 = 理想視口的寬度 = 布局視口的寬度。
- 單獨設置initial-scale或 width都會有兼容性問題,所以設置布局視口為理想視口的最佳方法是同時設置這兩個屬性。
- 即使設置了user-scalable = no,在Android Chrome瀏覽器中也可以強制啟用手動縮放。
設置 rem 基準值
核心代碼為如下
1// set 1rem = 邏輯像素(設備獨立像素) / 10
2function setRemUnit () {
3 var rem = document.documentElement.clientWidth / 10
4 // 375/10 = 37.5
5 docEl.style.fontSize = rem + 'px'
6}
7setRemUnit()
- 將html節點的font-size設置為頁面clientWidth(布局視口)的1/10,即:1rem = 布局視口的1/10
- 在iphone6下:docEl.clientWidth=設備獨立像素(邏輯像素)= 布局視口寬度 = 理想窗口寬度 = 375。此時:1rem = 375/10 +px = 37.5px
postcss-pxtorem將單位轉化為 rem
1module.exports = {
2 plugins: {
3 'autoprefixer': {
4 browsers: ['Android >= 4.0', 'iOS >= 7']
5 },
6 'postcss-pxtorem': {
7 rootValue: 37.5,
8 propList: ['*', '!font-size'],
9 selectorBlackList: ['van-circle__layer', 'ignore'],
10 }
11 }
12}
- rootValue是轉換px的基準值,參考設備iPhone6,設備寬度375px規則:基準值=當前設備寬度的1/10
- 基準值設置代碼中,在iPhone6設備設置的html—>font-size 也為37.5px
- 但是設計稿尺寸750px大小,所以量取設計稿量尺寸的時候需要除以2
rem布局的缺點
在響應式布局中,必須通過js來動態控制根元素font-size的大小,也就是說css樣式和js代碼有一定的耦合性,且必須將改變font-size的代碼放在css樣式之前。
2
vw適配
vw是基于Viewport視窗的長度單位,這里的視窗(Viewport)指的就是瀏覽器可視化的區域,而這個可視區域是window.innerWidth/window.innerHeight的大小,用圖簡單的示意如下
在CSS Values and Units Module Level 3中和Viewport相關的單位有四個,分別為vw、vh、vmin和vmax。
- vw:是Viewport's width的簡寫,1vw等于window.innerWidth的1%
- vh:和vw類似,是Viewport's height的簡寫,1vh等于window.innerHeihgt的1%
- vmin:vmin的值是當前vw和vh中較小的值
- vmax:vmax的值是當前vw和vh中較大的值
如果設計稿使用750px寬度,則100vw = 750px,即1vw = 7.5px。那么我們可以根據設計圖上的px值直接轉換成對應的vw值。如果不想自己計算,我們可以使用PostCSS的插件postcss-px-to-viewport,讓我們可以直接在代碼中寫px。
1{
2 loader: 'postcss-loader',
3 options: {
4 plugins: ()=>[
5 require('autoprefixer')({
6 browsers: ['last 5 versions']
7 }),
8 require('postcss-px-to-viewport')({
9 viewportWidth: 375, //視口寬度(數字)
10 viewportHeight: 1334, //視口高度(數字)
11 unitPrecision: 3, //設置的保留小數位數(數字)
12 viewportUnit: 'vw', //設置要轉換的單位(字符串)
13 selectorBlackList: ['.ignore', '.hairlines'], //不需要進行轉換的類名(數組)
14 minPixelValue: 1, //設置要替換的最小像素值(數字)
15 mediaQuery: false//允許在媒體查詢中轉換px(true/false)
16 })
17 ]
18}
3
搭配vw和rem
- 給根元素大小設置隨著視口變化而變化的vw單位,這樣就可以實現動態改變其大小。
- 限制根元素字體大小的最大最小值,配合body加上最大寬度和最小寬度。
1// rem 單位換算:定為 75px 只是方便運算,750px-75px、640-64px、1080px-108px,如此類推
2$vm_fontsize: 75; // iPhone 6尺寸的根元素大小基準值
3@function rem($px) {
4 @return ($px / $vm_fontsize ) * 1rem;
5}
6// 根元素大小使用 vw 單位
7$vm_design: 750;
8html {
9 font-size: ($vm_fontsize / ($vm_design / 2)) * 100vw;
10 // 同時,通過Media Queries 限制根元素最大最小值
11 @media screen and (max-width: 320px) {
12 font-size: 64px;
13 }
14 @media screen and (min-width: 540px) {
15 font-size: 108px;
16 }
17}
18// body 也增加最大最小寬度限制,避免默認100%寬度的 block 元素跟隨 body 而過大過小
19body {
20 max-width: 540px;
21 min-width: 320px;
22}
4
px 適配
就像開篇提到的,并不是說移動端就一定要使用相對長度單位,傳統的響應式布局依然是很好的選擇,尤其在新聞,社區等可閱讀內容較多的場景直接使用px單位可以營造更好地體驗。px方案可以讓大屏幕手機展示出更多的內容,更符合人們的閱讀習慣。
互聯網大廠的適配調研
1
rem適配例子
1.1 固定1倍vieport
注:下面描述的rem與px的對應關系是在設備獨立像素為375px(iPhone6/7/8)情況下。
拍拍貸m站首頁(https://m.ppdai.com/)
- 1rem = 20px
- 最大基準值為40px
- 限制頁面寬度750px
小紅書(https://www.xiaohongshu.com/)
- 1rem = 50px
- 最大基準值為60px
- 字體和頁面都進行縮放
- 配合media query,限制body的最大寬度
1@media screen and (min-width: 768px)
2body {
3 width: 450PX!important;
4}
微博(https://m.weibo.cn/)
- 字體和頁面都進行縮放
- 基準值是根據media query生成的
1.2 可縮放vieport
下面描述的rem與px的對應關系是在設備獨立像素為375px(iPhone6/7/8)、viewport scale 0.5的情況下。
美團(http://i.meituan.com/)
- 1rem = 100px
B站主站(https://m.bilibili.com/index.html)
- 1rem = 46.875px
搜狐(https://m.sohu.com/)
- 1rem = 75px
2
vm適配例子
拍拍貸借款頁(https://ld.ppdai.com/loan/mobile_base/373/25999?)
- 不限制頁面寬度
- 無兼容性處理,個人不推薦
3
vm+rem適配例子
京東(https://m.jd.com/)
- 固定vieport,元素布局上使用rem單位
- html元素的font-size使用vw + px fallback的形式
- 當頁面超過一定寬度時,根據media query設置font-size為px,優先級高于vw。
- 限制頁面寬度為1080px
image.png
網易(https://3g.163.com/touch/)
- 固定viewport,元素布局上使用rem單位
- html元素的font-size使用vw + px fallback的形式
- 使用media query設置根元素font-size中px的值
- 當頁面超過一定寬度時,px單位的優先級高于vw
- 限制布局寬度為768px
餓了么(https://h5.ele.me/msite/)
- 對viewport進行了縮放
- html元素的font-size依然由px指定
- 具體元素的布局上使用vw + rem fallbak的形式
- 沒有限制布局寬度
- css構建過程需要插件支持,可參考這個插件:pandaGao/stylus-px-to-relative-unit
4
px 方案例子
攜程(https://m.ctrip.com/html5/)
- 固定1倍vieport
- 布局方案:px+flex+百分比
- 設置body的最大寬度為max-width: 540px;
大眾點評(https://m.dianping.com/)
- 元素較豐富,采用px+flex布局,適配效果很好
知乎(https://www.zhihu.com/)
- 追求閱讀體驗的場景,使用px布局。
騰訊(https://xw.qq.com/)
- 首頁主要內容是新聞,為了更好的閱讀體驗,使用px布局。
陸金所(https://m.lu.com/)
- :root {font-size:10px;},并沒有根據屏幕的大小來設置不同的font-size
- 存在問題:布局頁面設成1rem時候,在chrome瀏覽器上任然12px,并不是10px
- 布局中雖然用了rem單位,但其實還是絕對單位方案
- 可能希望用戶在大屏手機上能看到更多內容吧
總結
- 新聞,社區等可閱讀內容較多的場景:px+flex+百分比
- 對視覺組件種類較多,視覺設計對元素位置的相對關系依賴較強的移動端頁面:vw + rem
以上只是自己的拙見以及自己這一兩年有關于移動端適配的一些探索,如果有不對之處,還請各路大神指正。
作者:子非魚
轉發鏈接:https://mp.weixin.qq.com/s/uQ8c2Z6GJr4eyH3kidZt3g