移動端適配 flexible rem 佈局方案全面講解

若是你看了不少篇文章,對 flexible 的解決方案一直還有一種不太瞭解的朦朧感受,那麼這篇文章會幫你從背景角度一步一步解析爲什麼會有 flexible 這套解決方案,以及這套解決方案是如何做用的。

爲何不能直接用 px 進行佈局

設計師基於 iphone6(375px 邏輯像素) 的頁面尺寸給了你一個很是簡單的設計稿
iphone6.jpgjavascript

你很快用以下的代碼實現了,在 chrome 控制檯打開 iphone6 查看效果,和設計稿絲絕不差。css

<div class="box1"></div>
<div class="box2"></div>
<style>
  .box1 {
    width: 100px;
    height: 100px;
    border: 1px solid red;
    position: fixed;
    left: 10px;
  }

  .box2 {
    width: 100px;
    height: 100px;
    border: 1px solid red;
    position: fixed;
    right: 10px;
  }
</style>

可是選則機型爲 iphone5 時頁面變成了這個樣子。
iphone5.jpg
會發如今 iphone5 的頁面下兩個方塊的間距和方塊大小比起來變得很是小,這樣咱們認爲這個網頁在不一樣屏幕尺寸的手機上產生了不一樣的顯示效果。
這個時候確定有同窗說了,那這個設計圖我用 vw 去還原就行了。的確使用 vw 還原設計圖是能夠作到的,但 vw 目前的兼容性仍然有問題,測試極可能甩過來一個 vivo-x7 告訴你頁面亂掉了。html

Flexible 是如何解決以上問題的

設計師在 375px ( iphone6 邏輯像素寬度 ) 的頁面上畫出了這個設計圖,則該 100px 的方塊在不一樣尺寸的手機上的大小實際應該爲 (100px/375px)*{屏幕邏輯像素寬度},然而咱們不可能爲每一種尺寸都在 css 上寫一個 px 寬度。這時可使用 rem,咱們能夠經過設置根節點的 font-size 來使不一樣尺寸的手機的 1rem 對應的 px 值不一樣。java

上面的話讀起來很繞,我寫起來很繞,那麼我將 100px 在 iphone5 和 iphone6 上的不一樣數值列個表android

手機型號 邏輯像素寬度 根節點 font-size rem 數值 px 數值
iphone5 320 px 64 px (100/75) rem (100/75)*64 px
iphone6 375 px 75 px (100/75) rem (100/75)*75 px

這樣在 iphone6 的屏幕尺寸上以 100px 渲染出來的盒子大小才能在 iphone5 的屏幕尺寸上以相同的比例渲染出來,在 iphone5 上渲染寬度爲 (100/75)*64px == 85.33px,因此 flexible 的源碼中refreshRem函數就是在計算不一樣手機尺寸應當設置的根節點 font-size,以下所示。git

function refreshRem() {
  var width = docEl.getBoundingClientRect().width
  if (width / dpr > 540) {
    // 這裏是爲了適配 ipad 和 android 平板橫屏的狀況(請暫時無視這個 if 語句)
    width = 540 * dpr
  }
  var rem = width / 10 // 將屏幕寬度分爲 10 份,每份爲 1rem
  docEl.style.fontSize = rem + 'px'
  flexible.rem = win.rem = rem
}

著名的 1px 像素問題

若是讀這篇文章同窗在以前有讀過其餘地方的文章會認爲我上面的解釋是錯誤的,由於其餘的文章在上面均使用的屏幕物理像素做爲基準,並配合設置 <viewport content="width=device-width,user-scalable=no,initial-scale=${scale}"> 實現,其實,若是沒有 1px 像素的問題是不須要設置 initial-scale 的。在文章的前半部分着重講解了如何用 rem 實現相似 vw 的效果,下面是關於 1px 像素問題的前因後果。github

什麼是 1px 像素問題

首先須要區分 物理像素 和 邏輯像素,物理像素即爲顯示器上的最小顯示單元,邏輯像素也就是 css 像素,是在網頁上渲染時的最小單位。而物理像素與邏輯像素之比 (物理像素/邏輯像素) 稱之爲 dpr (device pixel ratio),iphone 5的物理像素寬度爲 640px,邏輯像素寬度爲 320px,則 iphone5 的 dpr 爲 2。意味着在 css 上寫 1px 的寬度,在 iphone5 的顯示屏幕上實際渲染了 2px 的物理像素,使得咱們在 dpr>=2 的手機上設置 border-width:1px 看起來很是的粗。chrome

如何解決 1px 像素問題

爲了解決這個問題,flexible對上面的方案進行了優化。將 initial-scale 設置爲 1/dpr,這樣 dpr 爲 2 的手機就會將頁面縮小至 1/2 顯示,這個時候設置 border-width:1px 就真的是 1px 物理像素。可是不能由於這個修改影響其餘地方的佈局,其實解決方案也很簡單,就是將根節點的 font-size = font-size * dpr ,來將佈局大小放大回正常的樣子(但實際不是這樣寫的,是由於當設置了 scale = 1/2 時,documentn.documentElement.getBoundingClientRect().width 取得邏輯像素值會增大至 2 倍,因此不須要額外進行 根節點的 font-size = font-size * dpr)。瀏覽器

var width = docEl.getBoundingClientRect().width
var rem = width / 10 // 將屏幕寬度分爲 10 份,每份爲 1rem
docEl.style.fontSize = rem + 'px'

字體不能使用 rem,可能會出現小數

在 flexible 中有這樣一行代碼 docEl.setAttribute('data-dpr', dpr);這樣咱們能夠在本身的 css 中根據data-dpr來設置不一樣 dpr (能夠理解爲頁面縮放比例) 下的字體大小iphone

[data-dpr='1'] .text{
    font-size: 12px;
}
[data-dpr='2'] .text{
    font-size: 24px;
}
[data-dpr='3'] .text{
    font-size: 36px;
}

上面設計圖的正確還原方式

在你的瀏覽器中打開這段代碼並在移動端不一樣機型上進行切換,會獲得正確的設計圖還原效果。

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <script type="text/javascript" src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.2/??flexible_css.js,flexible.js">
  </script>
  <title>Document</title>
</head>

<body>
  <div class="box1"></div>
  <div class="box2"></div>
  <style>
    .box1 {
      width: 2.666666666666667rem; // 100px ÷ 37.5px(375px設計稿上的根 font-size 大小) = 2.666666666666667rem ,使用 css 預處理器的能夠寫一個函數
      height: 2.666666666666667rem;
      border: 1px solid red;
      position: fixed;
      left: 0.2666666666666667rem;
      top: 0.2666666666666667rem;
    }

    .box2 {
      width: 2.666666666666667rem;
      height: 2.666666666666667rem;
      border: 1px solid red;
      position: fixed;
      right: 0.2666666666666667rem;
      top: 0.2666666666666667rem;
    }
  </style>
</body>

</html>

Flexible 中源碼的其餘部分

但願看完這篇文章的你,再去這裏再好好看一下源碼的實現細節部分:flexible 源碼

相關文章
相關標籤/搜索