github倉庫:github.com/amfe/lib-fl…javascript
npm i -S amfe-flexible
複製代碼
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<script src="./node_modules/amfe-flexible/index.js"></script>
複製代碼
源碼只有短短43行,講解分爲兩部分:代碼中的註釋和與原理總結html
// 首先是一個當即執行函數,執行時傳入的參數是window和document
(function flexible (window, document) {
var docEl = document.documentElement // 返回文檔的root元素
var dpr = window.devicePixelRatio || 1
// 獲取設備的dpr,即當前設置下物理像素與虛擬像素的比值
// 調整body標籤的fontSize,fontSize = (12 * dpr) + 'px'
// 設置默認字體大小,默認的字體大小繼承自body
function setBodyFontSize () {
if (document.body) {
document.body.style.fontSize = (12 * dpr) + 'px'
} else {
document.addEventListener('DOMContentLoaded', setBodyFontSize)
}
}
setBodyFontSize();
// set 1rem = viewWidth / 10
// 設置root元素的fontSize = 其clientWidth / 10 + ‘px’
function setRemUnit () {
var rem = docEl.clientWidth / 10
docEl.style.fontSize = rem + 'px'
}
setRemUnit()
// 當頁面展現或從新設置大小的時候,觸發從新
window.addEventListener('resize', setRemUnit)
window.addEventListener('pageshow', function (e) {
if (e.persisted) {
setRemUnit()
}
})
// 檢測0.5px的支持,支持則root元素的class中有hairlines
if (dpr >= 2) {
var fakeBody = document.createElement('body')
var testElement = document.createElement('div')
testElement.style.border = '.5px solid transparent'
fakeBody.appendChild(testElement)
docEl.appendChild(fakeBody)
if (testElement.offsetHeight === 1) {
docEl.classList.add('hairlines')
}
docEl.removeChild(fakeBody)
}
}(window, document))
複製代碼
首先有幾個名詞須要解釋一下:前端
以rem爲單位,其值是相對root html元素,與em這個相對於父元素的單位不一樣。java
rem是flexible這套適配方案的核心node
rem的詳情點擊此處git
如上圖所示,clientWidth是元素內部的寬度,包括padding,但不包括border,margin和垂直的滾動條github
Element.clientWidth的詳情點擊此處npm
Document.documentElement 返回文檔的root元素,HTML文檔的元素瀏覽器
window.devicePixelRatio返回當前顯示設備下物理像素與設備獨立像素的比值,一樣也能夠解讀爲一個設備獨立像素是有幾個物理像素來展現的。app
物理像素是組成成像傳感器的最基礎單元的尺寸。
設備獨立像素是一個物理測量單位,是操做系統層面設置的虛擬像素。對於前端來講是定值。
當頁面設置了,那document.documentElement.clientWidth就等於設備獨立像素的寬度
window.devicePixelRatio的詳情點擊此處
首先經過設置meta,其主要做用的是width=device-width,使用這個以後,document.documentElement.clientWidth就等於設備獨立像素的寬度。
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
複製代碼
而後給root元素設置fontSize爲document.documentElement.clientWidth的十分之一,這樣1rem就等於document.documentElement.clientWidth/10,以此作適配。
rem並不是是完美的適配方案,使用了rem,最後渲染時仍是轉換成px,這時小數部分就四捨五入,有些結果並非咱們想要的。
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
複製代碼
meta標籤中的viewport做用是什麼呢?
viewport,在瀏覽器環境中,表示當前的瀏覽器的可視區域,正在被瀏覽的頁面,在這塊區域中被展現。
viewport,設置了viewport的初始尺寸,僅可以使用在移動端。
值 | 可能的子值 | 描述 |
---|---|---|
width | 整數 或 device-width | 定義viewport的寬度,用於展現網頁 |
height | 整數 or device-height | 定義viewport的高度,但幾乎未被瀏覽器使用 |
initial-scale | 一個大於0.0小於10.0的數字 | 定義了設備尺寸與viewport的比例 |
maximum-scale | 一個大於0.0小於10.0的數字 | 定義了能夠放大的最大值,大於等於minimum-scale,且瀏覽器的設置能夠忽略它,iOS10+默認忽略它 |
minimum-scale | 一個大於0.0小於10.0的數字 | 定義了能夠縮小的最小值,小於等於maximum-scale,且瀏覽器的設置能夠忽略它,iOS10+默認忽略它 |
user-scalable | yes 或 no | no,用戶不能縮放;yes,用戶能夠縮放,但瀏覽器的設置能夠忽略它,iOS10+默認忽略它 |