從原理到方案,一步步講解web移動端實現自適應等比縮放

  前言css

  在移動端作自適應,咱們經常使用的有媒體查詢,rem ,em,寬度百分比這幾種方案。可是都各有其缺點。html

  首先拿媒體查詢來講,在某一個寬度區間內只能使用一種樣式,爲了適應不一樣屏幕要,css的代碼量就會增多,而且後期頁面若是有改動,會變得愈來愈不易維護。em得根據父元素的字體大小來計算寬高,有很大侷限性。用百分比來設置寬度侷限性也大,首先是得計算每一個元素佔父元素的寬度,並且只能設置寬度的百分比,而高度則很難經過百分比來設置。因此最後的但願寄託在了rem上。webpack

  rem與pxcss3

  在講rem實現方案以前,咱們仍是按照國際慣例,講一下rem與px之間的關係。rem是指相對於根元素的字體大小的單位。這句話怎麼理解呢?請看下面的公式:web

  元素的rem值 = 元素的px值 / 根節點字體大小 ,咱們舉栗子說明一下。npm

  若是咱們設置了根元素的字體大小爲13px,那麼一個寬300px,高350px的元素對應的rem就是寬23.076923rem,高26.923076rem。瀏覽器

代碼以下:iphone

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圖來寫代碼,不用任何計算。提升了效率

相關文章
相關標籤/搜索