rem自适应布局插件
adaptive
也可以直接复制下方的js文件直接使用
index.js
js
var adaptive = {};
(function (win, lib) {
var doc = win.document;
var docEl = doc.documentElement;
// 设备像素比
var devicePixelRatio = win.devicePixelRatio;
// 我们设置的布局视口与理想视口的像素比
var dpr = 1;
// viewport缩放值
var scale = 1;
// 设置viewport
function setViewport() {
// 判断IOS
var isIPhone = /iphone/gi.test(win.navigator.appVersion);
if (lib.scaleType === 2 && isIPhone || lib.scaleType === 3) {
dpr = devicePixelRatio;
}
// window对象上增加一个属性,提供对外的布局视口与理想视口的值
win.devicePixelRatioValue = dpr;
// viewport缩放值,布局视口缩放后刚好显示成理想视口的宽度,页面就不会过长或过短了
scale = 1 / dpr;
// 获取已有的viewport
var hasMetaEl = doc.querySelector('meta[name="viewport"]');
var metaStr = 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no';
if (dpr === 1) {
metaStr = 'width=device-width, '.concat(metaStr);
}
if (!isIPhone && dpr !== 1) {
metaStr = metaStr.concat(', target-densitydpi=device-dpi');
}
// 如果有,改变之
if (hasMetaEl) {
hasMetaEl.setAttribute('content', metaStr);
}
// 如果没有,添加之
else {
var metaEl = doc.createElement('meta');
metaEl.setAttribute('name', 'viewport');
metaEl.setAttribute('content', metaStr);
if (docEl.firstElementChild) {
docEl.firstElementChild.appendChild(metaEl);
}
else {
var containDiv = doc.createElement('div');
containDiv.appendChild(metaEl);
docEl.appendChild(containDiv);
}
}
}
var newBase = 100;
lib.errDpr = 1;
function setRem() {
// 布局视口
// var layoutView = docEl.clientWidth; 也可以 获取布局视口的宽度
var layoutView;
if (lib.maxWidth) {
layoutView = Math.min(docEl.getBoundingClientRect().width, lib.maxWidth * dpr);
}
else {
layoutView = docEl.getBoundingClientRect().width;
}
// 为了计算方便,我们规定 1rem === 100px设计图像素,我们切图的时候就能快速转换
// 有人问,为什么不让1rem === 1px设计像素呢?
// 设计图一般是640或者750px
// 布局视口一般是320到1440
// 计算一个值,使layout的总宽度为 (desinWidth/100) rem
// 那么有计算公式:layoutView / newBase = desinWidth / 100
// newBase = 100 * layoutView / desinWidth
// newBase = 介于50到200之间
// 如果 1rem === 1px 设计像素,newBase就介于0.5到2之间,由于很多浏览器有最小12px限制,这个时候就不能自适应了
newBase = 100 * layoutView / lib.desinWidth * (lib.errDpr || 1);
docEl.style.fontSize = newBase + 'px';
// rem基准值改变后,手动reflow一下,避免旋转手机后页面自适应问题
doc.body&&(doc.body.style.fontSize = lib.baseFont / 100 + 'rem');
// 重新设置rem后的回调方法
lib.setRemCallback&&lib.setRemCallback();
lib.newBase = newBase;
}
var tid;
lib.desinWidth = 750;
lib.baseFont = 28;
// 局部刷新的时候部分chrome版本字体过大的问题
lib.reflow = function() {
docEl.clientWidth;
};
// 检查安卓下rem值是否显示正确
function checkRem() {
if (/android/ig.test(win.navigator.appVersion)) {
var hideDiv = document.createElement('p');
hideDiv.style.height = '1px';
hideDiv.style.width = '2.5rem';
hideDiv.style.visibility = 'hidden';
document.body.appendChild(hideDiv);
var now = hideDiv.offsetWidth;
var right = lib.newBase * 2.5;
if (Math.abs(right / now - 1) > 0.05) {
lib.errDpr = right / now;
setRem();
}
document.body.removeChild(hideDiv);
}
}
lib.init = function () {
// resize的时候重新设置rem基准值
// 触发orientationchange 事件时也会触发resize,故不需要再添加此事件了
win.addEventListener('resize', function () {
clearTimeout(tid);
tid = setTimeout(setRem, 300);
}, false);
// 浏览器缓存中读取时也需要重新设置rem基准值
win.addEventListener('pageshow', function (e) {
if (e.persisted) {
clearTimeout(tid);
tid = setTimeout(setRem, 300);
}
}, false);
// 设置body上的字体大小
if (doc.readyState === 'complete') {
doc.body.style.fontSize = lib.baseFont / 100 + 'rem';
checkRem();
}
else {
doc.addEventListener('DOMContentLoaded', function (e) {
doc.body.style.fontSize = lib.baseFont / 100 + 'rem';
checkRem();
}, false);
}
setViewport();
// 设置rem值
setRem();
// html节点设置布局视口与理想视口的像素比
docEl.setAttribute('data-dpr', dpr);
};
// 有些html元素只能以px为单位,所以需要提供一个接口,把rem单位换算成px
lib.remToPx = function (remValue) {
return remValue * newBase;
};
})(window, adaptive);
if (typeof module != 'undefined' && module.exports) {
module.exports = adaptive;
} else if (typeof define == 'function' && define.amd) {
define(function() {
return adaptive;
});
} else {
window.adaptive = adaptive;
}
在index.html使用
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/gh/jinweizhe/cdn/adaptive.js"></script>
<script>
window['adaptive'].desinWidth = 750// 设计图宽度
window['adaptive'].baseFont = 28// 没有缩放时的字体大小
window['adaptive'].maxWidth = 750// 页面最大宽度 默认540
window['adaptive'].init()// 调用初始化方法
</script>
<style>
div {
width: 0.3rem;
height: 0.3rem;
background-color: red;
}
</style>
</head>
<body>
<div>123</div>
</body>
</html>
hotcss
index.js文件这个文件里面自己无论设置了宽度多少,这个文件最终都会将屏幕平分16份,也就是说16rem刚好为100vw这样
js
;(function (window, document) {
'use strict'
//给hotcss开辟个命名空间,别问我为什么,我要给你准备你会用到的方法,免得用到的时候还要自己写。
var hotcss = {}
;(function () {
//根据devicePixelRatio自定计算scale
//可以有效解决移动端1px这个世纪难题。
var viewportEl = document.querySelector('meta[name="viewport"]'),
hotcssEl = document.querySelector('meta[name="hotcss"]'),
dpr = window.devicePixelRatio || 1,
maxWidth = 540, // 这里限制了最大宽度为540,这里可以自己根据设计图宽度自己改
// maxWidth = '100%', // 也可以这样写,限制最大宽度100%相当于没啥显示,默认100%宽(但是不管为多少,这个maxWidth必须要设置不能注释掉)
designWidth = 0
dpr = dpr >= 3 ? 3 : dpr >= 2 ? 2 : 1
//允许通过自定义name为hotcss的meta头,通过initial-dpr来强制定义页面缩放
if (hotcssEl) {
var hotcssCon = hotcssEl.getAttribute('content')
if (hotcssCon) {
var initialDprMatch = hotcssCon.match(/initial\-dpr=([\d\.]+)/)
if (initialDprMatch) {
dpr = parseFloat(initialDprMatch[1])
}
var maxWidthMatch = hotcssCon.match(/max\-width=([\d\.]+)/)
if (maxWidthMatch) {
maxWidth = parseFloat(maxWidthMatch[1])
}
var designWidthMatch = hotcssCon.match(/design\-width=([\d\.]+)/)
if (designWidthMatch) {
designWidth = parseFloat(designWidthMatch[1])
}
}
}
document.documentElement.setAttribute('data-dpr', dpr)
hotcss.dpr = dpr
document.documentElement.setAttribute('max-width', maxWidth)
hotcss.maxWidth = maxWidth
if (designWidth) {
document.documentElement.setAttribute('design-width', designWidth)
}
hotcss.designWidth = designWidth // 保证px2rem 和 rem2px 不传第二个参数时, 获取hotcss.designWidth是undefined导致的NaN
var scale = 1 / dpr,
content =
'width=device-width, initial-scale=' +
scale +
', minimum-scale=' +
scale +
', maximum-scale=' +
scale +
', user-scalable=no'
if (viewportEl) {
viewportEl.setAttribute('content', content)
} else {
viewportEl = document.createElement('meta')
viewportEl.setAttribute('name', 'viewport')
viewportEl.setAttribute('content', content)
document.head.appendChild(viewportEl)
}
})()
hotcss.px2rem = function (px, designWidth) {
//预判你将会在JS中用到尺寸,特提供一个方法助你在JS中将px转为rem。就是这么贴心。
if (!designWidth) {
//如果你在JS中大量用到此方法,建议直接定义 hotcss.designWidth 来定义设计图尺寸;
//否则可以在第二个参数告诉我你的设计图是多大。
designWidth = parseInt(hotcss.designWidth, 10)
}
return (parseInt(px, 10) * 320) / designWidth / 20
}
hotcss.rem2px = function (rem, designWidth) {
//新增一个rem2px的方法。用法和px2rem一致。
if (!designWidth) {
designWidth = parseInt(hotcss.designWidth, 10)
}
//rem可能为小数,这里不再做处理了
return (rem * 20 * designWidth) / 320
}
hotcss.mresize = function () {
//对,这个就是核心方法了,给HTML设置font-size。
var innerWidth =
document.documentElement.getBoundingClientRect().width ||
window.innerWidth
if (hotcss.maxWidth && innerWidth / hotcss.dpr > hotcss.maxWidth) {
innerWidth = hotcss.maxWidth * hotcss.dpr
}
if (!innerWidth) {
return false
}
document.documentElement.style.fontSize = (innerWidth * 20) / 320 + 'px'
hotcss.callback && hotcss.callback()
}
hotcss.mresize()
//直接调用一次
window.addEventListener(
'resize',
function () {
clearTimeout(hotcss.tid)
hotcss.tid = setTimeout(hotcss.mresize, 33)
},
false
)
//绑定resize的时候调用
window.addEventListener('load', hotcss.mresize, false)
//防止不明原因的bug。load之后再调用一次。
setTimeout(function () {
hotcss.mresize()
//防止某些机型怪异现象,异步再调用一次
}, 333)
window.hotcss = hotcss
//命名空间暴露给你,控制权交给你,想怎么调怎么调。
})(window, document)
index.html使用
js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./index.js"></script>
<style>
div {
width: 0.3rem;
height: 0.3rem;
background-color: red;
}
</style>
</head>
<body>
<div>123</div>
</body>
</html>
具体效果打开浏览器终端看根元素HTML的font-size大小