适配原理:
- 1rem = font-size
- font-size = 视口宽 / 系数
- init-scale = 1 / 设备像素比
适配思路:
首先通过JS动态生成meta标签,再通过监听resize事件来获取实时的视口宽,最后通过计算得出HTML元素的font-size。
因为CSS中的rem单位会根据此font-size进行等比变化,所以每次窗口调整时,CSS中使用了rem进行宽高设置的元素也会随之产生缩放效果。但为了防止元素无限缩放而影响视觉,所以限制了maxWidth和minWidth。
关于系数:
直接将视口宽作为font-size通常不便于计算,所以我们选择一个系数来简化数字。将设计稿的宽度与系数相除,得出设计稿原本的font-size,再将设计稿中元素的宽高与该font-size相除,得出元素的rem。
(function () {
// 使用严格模式
"use strict";
// 获取HTML元素、meta标签、设备像素比,设置缩放阈值
var docEl = document.documentElement,
viewportEl = document.querySelector('meta[name="viewport"]'),
dpr = window.devicePixelRatio || 1,
maxWidth = 540,
minWidth = 320;
// 将设备像素比限定在1-3之间
dpr = dpr >= 3 ? 3 : dpr >= 2 ? 2 : 1;
// 向HTML增加属性,记录设备像素比、缩放阈值
docEl.setAttribute("data-dpr", dpr);
docEl.setAttribute("max-width", maxWidth);
docEl.setAttribute("min-width", minWidth);
// 计算缩放值,拼接meta的content
var scale = 1 / dpr,
content =
"width=device-width, initial-scale=" +
scale +
", maximum-scale=" +
scale +
", minimum-scale=" +
scale +
", user-scalable=no";
// 如果不存在meta标签,则创建后再设置属性
if (viewportEl) {
viewportEl.setAttribute("content", content);
} else {
viewportEl = document.createElement("meta");
viewportEl.setAttribute("name", "viewport");
viewportEl.setAttribute("content", content);
document.head.appendChild(viewportEl);
}
// 页面启动时立刻设置font-size
setRemUnit();
// 绑定监听事件,当窗口调整时重新设置font-size
window.addEventListener("resize", setRemUnit);
// 设置font-size的函数
function setRemUnit() {
// 设定系数
var ratio = 18.75;
// 获取视口宽
var viewWidth = docEl.getBoundingClientRect().width || window.innerWidth;
// 如果视口宽过大或过小,则进行调整
if (maxWidth && viewWidth / dpr > maxWidth) {
viewWidth = maxWidth * dpr;
} else if (minWidth && viewWidth / dpr < minWidth) {
viewWidth = minWidth * dpr;
}
// 计算font-size
docEl.style.fontSize = viewWidth / ratio + "px";
}
})();