1. 程式人生 > >基於REM的移動端自適應佈局方案

基於REM的移動端自適應佈局方案

背景

現在工作中有超過一半的時間用於移動端專案的開發,包括app嵌入頁,微信頁面和移動wap頁。

開發移動端頁面跟開發PC頁面的一個大區別就是移動端對響應式佈局的要求更高,不能像PC頁面一樣設計幾個斷點利用媒體查詢,兩邊留空白就解決。移動端頁面需要把螢幕空間都利用上,而移動裝置的尺寸和解析度多種多樣,解決移動端頁面的自適應佈局問題是搭建新的移動端專案的重點和難點。

經過研究,我在公司的多個移動端專案使用了REM佈局來解決移動端自適應佈局的問題。

REM介紹

rem(font size of the root element)是指相對於根元素的字型大小的單位。簡單的說它就是一個相對單位,rem佈局是一個流行的解決移動端響應式佈局的方案。在頁面初始化時,使用JS根據螢幕的尺寸和dpr等資訊設定rem的大小,而在css中寫下元素的高度等資訊時,使用rem。如將rem設定為100px,則元素的高度為36px時,需要將元素的高度寫成0.36rem。

傳統的REM佈局遇到的問題

以100畫素為例,很多常見的屬性如字型大小需要寫成0.12rem等,可讀性較差,輸入起來也不方便,降低了工作效率。

解決方案

在webpack中使用px2rem-loader。用法如下


rules: [
  {
    test: /\.css$/,
    use: ['style-loader', 'css-loader', 'px2rem-loader?remUnit=75&remPrecision=8']
  }
]

這樣便可以應對常見的750px的設計圖,直接按照設計圖的尺寸來填寫屬性大小就好,
注意,還需要在html檔案中引入flexible檔案


<script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.2/??flexible_css.js,flexible.js"></script>

踩到的坑

微信瀏覽器如果退回的話,頁面被快取,但是js檔案沒有重新呼叫,會導致佈局混亂。需要呼叫pageshow事件來解決

e.addeventListener('pageshow', function(e) {
	// d的作用是重新設定documentElement的fontsize為clientWidth的1/10
	e.persisted&&d()
})

深入

你也許會對flexible.js做了什麼比較感興趣。在這之前,需要簡單瞭解一下viewport的知識

viewport
viewport meta標籤

viewport meta標籤有六個屬性

  1. width:設定layout viewport 的寬度,為一個正整數,或字串”width-device”
  2. initial-scale:設定頁面的初始縮放值,為數字,可帶小數
  3. minimum-scale: 允許使用者的最小縮放值,為數字,可帶小數
  4. maximum-scale:允許使用者的最大縮放值,為數字,可帶小數
  5. height 設定layout viewport 的高度
  6. user-scalable 是否允許使用者進行縮放,值為”no”或”yes”
三種viewport
  1. layout viewport 佈局視窗

網站的寬度,可以通過document.documentElement.clientWidth獲取,通過viewport meta標籤設定

  1. visual viewport——視覺視窗

代表瀏覽器可視區域的大小,可以通過 document.documentElement.innerWidth來獲取

  1. ideal viewport——理想視窗

跟移動裝置相關的viewport,移動裝置的寬度。ihpone的值是320

他們之間的關係

visual viewport width = ideal viewport width / zoom factor

zoom factor可以設定initial-scale來控制
當visual viewport = layout viewport時,頁面無水平滾動條,剛好顯示全部內容

如果不設定initial-scale,通過設定viewport meta的width為device-width,可以令layout viewport等於ideal viewport,從而達到頁面無水平滾動條的效果

lib-flexible原理
  1. 獲取dpr和設定dpr的倒數scale
  2. 動態生成viewport meta,initial-scale值為scale
  3. 設定rem為clientWidth(layoutview port width) 的1 / 10

這時我們我們開發專案只要注意螢幕的寬度是10rem就可以了