flexible.js 2.0 分支的源码并不多,总共不到 50 行,下面先分析每段代码的用处:
::: warning flexible.js 官方已不在维护,目前推行 vw 适配方案,本文只是为了分析它的原理。 :::
(function flexible (window, document)){}(window, document))
上面代码是一个 IIFE(立即执行)函数,当浏览器解析完这个函数后会立即执行。使用 IIFE 的原因在于隔离作用域,不至于污染全局作用域。IIEF 传入 window 和 document 参数可以减少作用域的查找,同时有也利于代码混淆。关于 IIFE 的更多用处请浏览 IIFE详解。
var docEl = document.documentElement
获取文档的根节点(html 标签)。
var dpr = window.devicePixelRatio || 1
上面的代码是获取设备的 DPR,如未获取到默认设为 1。DPR 指的是设备物理像素和设备独立像素的比例,DPR >= 2 以上的为视网膜设备。window.devicePixelRatio
的支持情况请在 can i use 查看。
function setBodyFontSize () {
if (document.body) {
document.body.style.fontSize = (12 * dpr) + 'px'
}
else {
document.addEventListener('DOMContentLoaded', setBodyFontSize)
}
}
上面的代码从函数名可以看出是用于设置 body 字体大小,这个函数会在 DOM 加载完成后调用,body 字体大小会被设置为 12 倍 DPR 像素。不过个人感觉下面的写法更简洁:
function setBodyFontSize () {
document.addEventListener('DOMContentLoaded', function(){
document.body.style.fontSize = (12 * dpr) + 'px'
})
}
DOMContentLoaded
事件会在 DOM 内容加载完毕时触发,无需等待文档中的外部资源(image、video)载入。关于页面生命周期请浏览页面生命周期。
::: warning 从 issues 看来设置 body size 似乎会造成怪异现象,我之前也确实出现过字体在一瞬间从大变小的问题。关于这段代码的用途请看官方的解释。 :::
function setRemUnit () {
var rem = docEl.clientWidth / 10
docEl.style.fontSize = rem + 'px'
}
上面的代码是将根节点的字体大小设置为浏览器可视区域宽度的 10%,也就是相当于 1rem 的大小。
window.addEventListener('resize', setRemUnit)
上面的代码会当浏览器窗口大小改变时重新设置根节点的字体大小。
window.addEventListener('pageshow', function (e) {
if (e.persisted) {
setRemUnit()
}
})
上面的代码是会在浏览器前进后退到当前网页时触发,这样做的目的在于解决浏览器的“往返缓存”问题。关于浏览器的往返缓存请浏览 浏览器前进/后退缓存(BF Cache)。
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)
}
上面的代码用于检测分辨率大于等于 2 的设备中的浏览器是否支持 0.5 px,如果支持则在 html 标签在添加 hairlines
类。其思路是通过设置一个 div 元素的 border 为 0.5px,然后获取这个 div 元素的高度,如果高度为 1 则表示当前浏览器支持 0.5px 写法。这段代码的是为了编写 1px 的兼容代码:
.hairlines .bb{
border-bottom:0.5px !important;
}
从上面的分析可以看出 flexible.js 主要是通过动态辨别设备的 DPR 设置根节点的字体大小,并搭配能跟随根节点字体大小而改变大小的 rem 单位来实现在不同终端适配的。