前言
在移動端做自適應,我們常用的有媒體查詢,rem ,em,寬度百分比這幾種方案。但是都各有其缺點。
首先拿媒體查詢來說,在某一個寬度區間內只能使用一種樣式,為了適應不同屏幕要,css的代碼量就會增多,並且后期頁面如果有改動,會變得越來越不易維護。em得根據父元素的字體大小來計算寬高,有很大局限性。用百分比來設置寬度局限性也大,首先是得計算每個元素占父元素的寬度,而且只能設置寬度的百分比,而高度則很難通過百分比來設置。所以最后的希望寄托在了rem上。
rem與px
在講rem實現方案之前,我們還是按照國際慣例,講一下rem與px之間的關系。rem是指相對於根元素的字體大小的單位
。這句話怎么理解呢?請看下面的公式:
元素的rem值 = 元素的px值 / 根節點字體大小 ,我們舉栗子說明一下。
如果我們設置了根元素的字體大小為13px,那么一個寬300px,高350px的元素對應的rem就是寬23.076923rem,高26.923076rem。
代碼如下:
html{ font-size: 13px; } div{ width: 23.076923rem; // 23.076923rem = 300px / 13px height: 26.923076rem;// 26.923076rem = 350px / 13px
}
可以通過查看器對上面的公式進行驗證,如圖:
可以看出,瀏覽器根據rem值自動計算得到div的寬高分別為300px,350px。由此我們可以把根節點字體大小作為自變量,元素寬高作為因變量(注意:此處的寬高指的是瀏覽器通過換算得到的元素px值,而不是rem值)。當我們通過JavaScript動態改變根節點字體大小時,瀏覽器就會重新計算元素的寬高,也就可以實現了動態縮放。但是怎么把縮放跟屏幕寬度聯系起來呢?
回答上述問題之前我們得知道,任何的縮放都必須有一個參考點,才能稱為縮放,這是我們平時很容易忽略的一點。所以接下來我們以iphone6的設計稿為參考點,選擇iphone6是因為現在大多數的UI出圖都是iphone6的尺寸,我們寫好css代碼后,瀏覽器就可以在此基礎上計算元素px值,從而達到縮放的效果。
同樣通過例子來說明:UI圖標注div寬300px, 高350px, 字體大小20px。
實現
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height"/> <title>Title</title> <link rel="stylesheet" href="./index.css"> </head> <body> <div> hello 大家 </div> </body> <script src="./src/index.js"></script> </html>
index.css
div{ font-size: 0.533333rem; // 0.533333rem = 20px / 37.5px width: 8rem; // 8rem = 300px / 37.5px height: 9.333333rem; // 9.333333rem = 350px / 37.5px margin: 0 auto; background-color: lightskyblue; }
注意此處並沒有設置根節的font-size為37.5px。但是計算rem時卻使用了它,因為37.5px即為iphone6屏幕的十分之一,就是為了把iphone6作為參考基准,並且這樣元素的寬高與屏幕的寬度之間就有了一個比例關系。當通過js通過改變font-size的值,並且保證這個值始終與屏幕寬度有一個比例關系時,瀏覽器根據公式重新計算元素的寬高就和屏幕寬度也就有了一個比例關系。當屏幕變寬,元素放大,當屏幕變窄元素縮小。
index.js
var htmlWidth = document.documentElement.clientWidth || document.body.clientWidth //獲取屏幕寬度 var htmlDom = document.getElementsByTagName('html')[0] //獲取html htmlDom.style.fontSize = htmlWidth / 10 + 'px'; //設置html字體大小為屏幕的十分之一 //監聽窗口大小改變 window.addEventListener('resize', () => { var htmlWidth = document.documentElement.clientWidth || document.body.clientWidth var htmlDom = document.getElementsByTagName('html')[0] htmlDom.style.fontSize = htmlWidth / 10 + 'px'; })
這樣基本上就已經可以實現自適應了
但是還有一個重要的問題沒解決。我們不能每一個元素的rem值都像上面那樣挨個手動計算,這樣效率太低。
下面介紹兩種解決方案:
第一種:利用scss定義函數實現自動轉換
新建index2.scss文件
@function px2rem($px){ $rem:37.5px; @return ($px / $rem) + rem; } div{ font-size: px2rem(20px); width: px2rem(300px); height: px2rem(350px); margin: 0 auto; background-color: lightskyblue; }
然后看看IDE自動幫我們編譯后的文件index2.css, 和index.css文件一模一樣
div{ font-size: 0.533333rem; width: 8rem; height: 9.333333rem; margin: 0 auto; background-color: lightskyblue; }
第二種:借助webpack,px2rem-loader實現
先下載各種loader
npm install style-loader css-loader px2rem-loader --save-dev
配置webpack
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: [{
loader: "css-loader", }, {
loader: 'px2rem-loader?remUnit=37.5&remPrecision=6' }], })
}
index3.css
div{ font-size: 20px; width: 300px; height: 350px; margin: 0 auto; background-color: lightskyblue; }
通過webpack編譯過后的index.css3文件還是和index.css文件一樣。這樣就直接可以按照ui圖來寫代碼,不用任何計算。提高了效率