<!doctype html> <html> <head> <meta charset="utf-8"> <title>无标题文档</title> <meta name="viewport" content="initial-scale=1.0,user-scalable=no,maximum-scale=1,width=device-width" /> </head> <body> <script> var throttle = function(fn,timeout ){ var timer; return function(){ var self = this, args = arguments; clearTimeout( timer ); timer = setTimeout(function(){ fn.apply( self, args ); }, timeout ); }; }; var doc=document; screenWd=doc.documentElement.clientWidth; doc.getElementsByTagName("html")[0].style.fontSize=screenWd/10+'px'; // console.log(document.getElementsByTagName("html")[0].style.fontSize); window.addEventListener("resize", throttle(function(){ //监听绑定 document.getElementsByTagName("html")[0].style.fontSize=document.documentElement.clientWidth/10+'px'; },150),false); </script> <style> *{ margin:0; padding:0;} html{ min-320px; font-size:62.5%;} #header{ 10rem; height:1.8rem; line-height:1.8rem;background:-webkit-linear-gradient(top,#333,#999); text-align:center; color:#fff;} .warp{ 10rem; margin:0 auto; height:300px;} /* 总共分20分 左边 10 间隙1 2隔间系2*/ .div1{ 3rem;float:left;height:10rem;background:#eee} .div2{ 3rem; margin-left:0.5rem;float:left;height:11rem; background:#303} .div3{ 3rem; margin-left:0.5rem;float:left;height:8rem;background:#666} #footer{ 100%; height:1.8rem; line-height:1.8rem; background:#333; text-align:center; color:#fff; position:absolute; bottom:0; left:0;} </style> <header id="header">头部观察文字大小</header> <div class="warp"> <div class="div1">left</div> <div class="div2">中间</div> <div class="div3">右侧eft</div> </div> <footer id="footer">底部</footer> </body> </html>
rem两个比较好的框架
淘宝Flexible https://github.com/amfe/lib-flexible
使用Flexible实现手淘H5页面的终端适配 https://github.com/amfe/article/issues/17
adaptive https://github.com/finance-sh/adaptive
网易的rem函数
<script type="text/javascript"> var Dpr = 1, uAgent = window.navigator.userAgent; var isIOS = uAgent.match(/iphone/i); var isYIXIN = uAgent.match(/yixin/i); var is2345 = uAgent.match(/Mb2345/i); var ishaosou = uAgent.match(/mso_app/i); var isSogou = uAgent.match(/sogoumobilebrowser/ig); var isLiebao = uAgent.match(/liebaofast/i); var isGnbr = uAgent.match(/GNBR/i); function resizeRoot(){ var wWidth = (screen.width > 0) ? (window.innerWidth >= screen.width || window.innerWidth == 0) ? screen.width : window.innerWidth : window.innerWidth, wDpr, wFsize; var wHeight = (screen.height > 0) ? (window.innerHeight >= screen.height || window.innerHeight == 0) ? screen.height : window.innerHeight : window.innerHeight; if (window.devicePixelRatio) { wDpr = window.devicePixelRatio; } else { wDpr = isIOS ? wWidth > 818 ? 3 : wWidth > 480 ? 2 : 1 : 1; } if(isIOS) { wWidth = screen.width; wHeight = screen.height; } // if(window.orientation==90||window.orientation==-90){ // wWidth = wHeight; // }else if((window.orientation==180||window.orientation==0)){ // } if(wWidth > wHeight){ wWidth = wHeight; } wFsize = wWidth > 1080 ? 144 : wWidth / 7.5; wFsize = wFsize > 32 ? wFsize : 32; window.screenWidth_ = wWidth; if(isYIXIN || is2345 || ishaosou || isSogou || isLiebao || isGnbr){//YIXIN 和 2345 这里有个刚调用系统浏览器时候的bug,需要一点延迟来获取 setTimeout(function(){ wWidth = (screen.width > 0) ? (window.innerWidth >= screen.width || window.innerWidth == 0) ? screen.width : window.innerWidth : window.innerWidth; wHeight = (screen.height > 0) ? (window.innerHeight >= screen.height || window.innerHeight == 0) ? screen.height : window.innerHeight : window.innerHeight; wFsize = wWidth > 1080 ? 144 : wWidth / 7.5; wFsize = wFsize > 32 ? wFsize : 32; // document.getElementsByTagName('html')[0].dataset.dpr = wDpr; document.getElementsByTagName('html')[0].style.fontSize = wFsize + 'px'; document.getElementById("fixed").style.display="none"; },500); }else{ // document.getElementsByTagName('html')[0].dataset.dpr = wDpr; document.getElementsByTagName('html')[0].style.fontSize = wFsize + 'px'; document.getElementById("fixed").style.display="none"; } // alert("fz="+wFsize+";dpr="+window.devicePixelRatio+";UA="+uAgent+";width="+wWidth+";sw="+screen.width+";wiw="+window.innerWidth+";wsw="+window.screen.width+window.screen.availWidth); } resizeRoot(); </script>
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; }
<script> // 设计图宽度 window['adaptive'].desinWidth = 640; // body 字体大小 会将body字体大小设置为 baseFont / 100 + 'rem' 750的设计图一般设置为28,640的设计图一般设置为24 window['adaptive'].baseFont = 24; /* // 显示最大宽度 可选 window['adaptive'].maxWidth = 480; // rem值改变后执行方法 可选 window['adaptive'].setRemCallback = function () { alert(1) } // scaleType 1:iphone andriod下viewport均无缩放 2:iphone下viewport有缩放,andriod没有 3:iphone andriod下viewport均有缩放; 默认值为1 window['adaptive'].scaleType = 1; */ // 初始化 window['adaptive'].init(); </script>