github倉(cāng)庫(kù):github.com/amfe/lib-fl…
使用方法
安裝
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>
// 首先是一個(gè)立即執(zhí)行函數(shù)葡缰,執(zhí)行時(shí)傳入的參數(shù)是window和document
(function flexible (window, document) {
var docEl = document.documentElement // 返回文檔的root元素
var dpr = window.devicePixelRatio || 1
// 獲取設(shè)備的dpr闸餐,即當(dāng)前設(shè)置下物理像素與虛擬像素的比值
// 調(diào)整body標(biāo)簽的fontSize管引,fontSize = (12 * dpr) + 'px'
// 設(shè)置默認(rèn)字體大小,默認(rèn)的字體大小繼承自body
function setBodyFontSize () {
if (document.body) {
document.body.style.fontSize = (12 * dpr) + 'px'
} else {
document.addEventListener('DOMContentLoaded', setBodyFontSize)
}
}
setBodyFontSize();
// set 1rem = viewWidth / 10
// 設(shè)置root元素的fontSize = 其clientWidth / 10 + ‘px’
function setRemUnit () {
var rem = docEl.clientWidth / 10
docEl.style.fontSize = rem + 'px'
}
setRemUnit()
// 當(dāng)頁(yè)面展示或重新設(shè)置大小的時(shí)候缸浦,觸發(fā)重新
window.addEventListener('resize', setRemUnit)
window.addEventListener('pageshow', function (e) {
if (e.persisted) {
setRemUnit()
}
})
// 檢測(cè)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))
原理解析
源碼只有短短43行,講解分為兩部分:代碼中的注釋和與原理總結(jié)
源碼注釋
// 首先是一個(gè)立即執(zhí)行函數(shù)竿奏,執(zhí)行時(shí)傳入的參數(shù)是window和document(function flexible (window, document) { var docEl = document.documentElement // 返回文檔的root元素 var dpr = window.devicePixelRatio || 1 // 獲取設(shè)備的dpr,即當(dāng)前設(shè)置下物理像素與虛擬像素的比值 // 調(diào)整body標(biāo)簽的fontSize腥放,fontSize = (12 * dpr) + 'px' // 設(shè)置默認(rèn)字體大小泛啸,默認(rèn)的字體大小繼承自body function setBodyFontSize () { if (document.body) { document.body.style.fontSize = (12 * dpr) + 'px' } else { document.addEventListener('DOMContentLoaded', setBodyFontSize) } } setBodyFontSize(); // set 1rem = viewWidth / 10 // 設(shè)置root元素的fontSize = 其clientWidth / 10 + ‘px’ function setRemUnit () { var rem = docEl.clientWidth / 10 docEl.style.fontSize = rem + 'px' } setRemUnit() // 當(dāng)頁(yè)面展示或重新設(shè)置大小的時(shí)候,觸發(fā)重新 window.addEventListener('resize', setRemUnit) window.addEventListener('pageshow', function (e) { if (e.persisted) { setRemUnit() } }) // 檢測(cè)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)) 復(fù)制代碼
原理總結(jié)
首先有幾個(gè)名詞需要解釋一下:
rem
以rem為單位候址,其值是相對(duì)root html元素,與em這個(gè)相對(duì)于父元素的單位不同伍纫。
rem是flexible這套適配方案的核心
Element?.clientWidth
<figcaption style="box-sizing: border-box; outline: 0px; display: block; text-align: center; margin: 8px; color: rgb(153, 153, 153); font-size: 14px; overflow-wrap: break-word;"></figcaption>
如上圖所示宗雇,clientWidth是元素內(nèi)部的寬度,包括padding莹规,但不包括border赔蒲,margin和垂直的滾動(dòng)條
Element?.clientWidth的詳情點(diǎn)擊此處
Document?.document?Element
Document?.document?Element 返回文檔的root元素,HTML文檔的元素
window.devicePixelRatio
window.devicePixelRatio返回當(dāng)前顯示設(shè)備下物理像素與設(shè)備獨(dú)立像素的比值良漱,同樣也可以解讀為一個(gè)設(shè)備獨(dú)立像素是有幾個(gè)物理像素來(lái)展示的舞虱。
物理像素
物理像素是組成成像傳感器的最基礎(chǔ)單元的尺寸。
設(shè)備獨(dú)立像素 - Device Independent Pixels(dip)
設(shè)備獨(dú)立像素是一個(gè)物理測(cè)量單位母市,是操作系統(tǒng)層面設(shè)置的虛擬像素矾兜。對(duì)于前端來(lái)說(shuō)是定值。
當(dāng)頁(yè)面設(shè)置了患久,那document.documentElement.clientWidth就等于設(shè)備獨(dú)立像素的寬度
window.devicePixelRatio的詳情點(diǎn)擊此處
總結(jié)
首先通過(guò)設(shè)置meta椅寺,其主要作用的是width=device-width,使用這個(gè)之后蒋失,document.documentElement.clientWidth就等于設(shè)備獨(dú)立像素的寬度返帕。
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
然后給root元素設(shè)置fontSize為document.documentElement.clientWidth的十分之一,這樣1rem就等于document.documentElement.clientWidth/10,以此做適配篙挽。
rem并非是完美的適配方案荆萤,使用了rem,最后渲染時(shí)還是轉(zhuǎn)換成px,這時(shí)小數(shù)部分就四舍五入链韭,有些結(jié)果并不是我們想要的偏竟。
meta viewport
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
meta標(biāo)簽中的viewport作用是什么呢?
viewport敞峭,在瀏覽器環(huán)境中踊谋,表示當(dāng)前的瀏覽器的可視區(qū)域,正在被瀏覽的頁(yè)面儡陨,在這塊區(qū)域中被展示褪子。
viewport,設(shè)置了viewport的初始尺寸骗村,僅可使用在移動(dòng)端嫌褪。
值 | 可能的子值 | 描述 |
---|---|---|
width | 整數(shù) 或 device-width | 定義viewport的寬度,用于展示網(wǎng)頁(yè) |
height | 整數(shù) or device-height | 定義viewport的高度胚股,但幾乎未被瀏覽器使用 |
initial-scale | 一個(gè)大于0.0小于10.0的數(shù)字 | 定義了設(shè)備尺寸與viewport的比例 |
maximum-scale | 一個(gè)大于0.0小于10.0的數(shù)字 | 定義了可以放大的最大值笼痛,大于等于minimum-scale,且瀏覽器的設(shè)置可以忽略它琅拌,iOS10+默認(rèn)忽略它 |
minimum-scale | 一個(gè)大于0.0小于10.0的數(shù)字 | 定義了可以縮小的最小值缨伊,小于等于maximum-scale,且瀏覽器的設(shè)置可以忽略它进宝,iOS10+默認(rèn)忽略它 |
user-scalable | yes 或 no | no刻坊,用戶不能縮放;yes党晋,用戶可以縮放谭胚,但瀏覽器的設(shè)置可以忽略它,iOS10+默認(rèn)忽略它 |