由于移动端特殊性,本文讲的是如何使用rem实现自适应,或叫rem响应式布局,通过使用一个脚本就可以rem自适应,不用再为各种设备宽度不同而烦恼如何实现自适应的问题。
rem是相对于根元素,这样就意味着,我们只需要在根元素确定一个px字号,则可以来算出元素的宽高。1rem=16px(浏览器html的像素,可以设定这个基准值),假如浏览器的html设为64px,则下面的元素则1rem=64px来运算。
阿里团队开源的一个库。使用flexible.js轻松搞定各种不同的移动端设备兼容自适应问题。
在这里找到了一个精简版的flexible.min.js,可以适配所有的移动端:
代码如下:
//designWidth:设计稿的实际宽度值,需要根据实际设置
//maxWidth:制作稿的最大宽度值,需要根据实际设置
//这段js的最后面有两个参数记得要设置,一个为设计稿实际宽度,一个为制作稿最大宽度,例如设计稿为750,最大宽度为750,则为(750,750)
;(function(designWidth, maxWidth) {
var doc = document,
win = window,
docEl = doc.documentElement,
remStyle = document.createElement("style"),
tid;
function refreshRem() {
var width = docEl.getBoundingClientRect().width;
maxWidth = maxWidth || 540;
width>maxWidth && (width=maxWidth);
var rem = width * 100 / designWidth;
remStyle.innerHTML = 'html{font-size:' + rem + 'px;}';
}
if (docEl.firstElementChild) {
docEl.firstElementChild.appendChild(remStyle);
} else {
var wrap = doc.createElement("div");
wrap.appendChild(remStyle);
doc.write(wrap.innerHTML);
wrap = null;
}
//要等 wiewport 设置好后才能执行 refreshRem,不然 refreshRem 会执行2次;
refreshRem();
win.addEventListener("resize", function() {
clearTimeout(tid); //防止执行两次
tid = setTimeout(refreshRem, 300);
}, false);
win.addEventListener("pageshow", function(e) {
if (e.persisted) { // 浏览器后退的时候重新计算
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}
}, false);
if (doc.readyState === "complete") {
doc.body.style.fontSize = "16px";
} else {
doc.addEventListener("DOMContentLoaded", function(e) {
doc.body.style.fontSize = "16px";
}, false);
}
})(750, 750);
使用方法:·
1.复制上面这段代码到你的页面的头部的script标签的最前面。
2.根据设计稿大小,调整里面的最后两个参数值。
3.使用1rem=100px转换你的设计稿的像素,例如设计稿上某个块是100px300px,换算成rem则为1rem3rem。
上面的代码,如果在uc浏览器下横屏与竖屏转换,发现代码并没有自适应,则通过下面进行解决bug:
1
2
3
4
5
已经找到兼容方案,可通过js在页面的head里生成定义了html元素font-size的style元素来解决!
如下:
注意还加了important来提高权重
该代码版本区别于手淘的rem换算方法。使用的是1rem=100px的换算。·
假如你有一个块是.box{width:120px;height:80px;} 转为rem则为.box{width:1.2rem; height:.8rem;}
基本的HTML模板·
你也可以直接复制下面这个基础的HTML模板。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport">
<meta content="yes" name="apple-mobile-web-app-capable">
<meta content="black" name="apple-mobile-web-app-status-bar-style">
<meta content="telephone=no" name="format-detection">
<meta content="email=no" name="format-detection">
<meta name="description" content="不超过150个字符"/>
<meta name="keywords" content=""/>
<meta content="caibaojian" name="author"/>
<title>前端开发博客</title>
<link rel="stylesheet" href="base.css">
<script type="text/javascript">
//引入该flexible.min.js
!function(e,t){function n(){var n=l.getBoundingClientRect().width;t=t||540,n>t&&(n=t);var i=100*n/e;r.innerHTML="html{font-size:"+i+"px;}"}var i,d=document,o=window,l=d.documentElement,r=document.createElement("style");if(l.firstElementChild)l.firstElementChild.appendChild(r);else{var a=d.createElement("div");a.appendChild(r),d.write(a.innerHTML),a=null}n(),o.addEventListener("resize",function(){clearTimeout(i),i=setTimeout(n,300)},!1),o.addEventListener("pageshow",function(e){e.persisted&&(clearTimeout(i),i=setTimeout(n,300))},!1),"complete"===d.readyState?d.body.style.fontSize="16px":d.addEventListener("DOMContentLoaded",function(e){d.body.style.fontSize="16px"},!1)}(750,750);
</script>
</head>
<body>
<!-- 正文 -->
</body>
</html>
base.css:
body, dl, dd, ul, ol, h1, h2, h3, h4, h5, h6, pre, form, input, textarea, p, hr, thead, tbody, tfoot, th, td {
margin: 0;
padding: 0;
}
ul, ol {
list-style: none;
}
a {
text-decoration: none;
}
html {
-ms-text-size-adjust: none;
-webkit-text-size-adjust: none;
text-size-adjust: none;
}
body {
line-height: 1.5;
font-size: 14px;
}
body, button, input, select, textarea {
font-family: 'helvetica neue', tahoma, 'hiragino sans gb', stheiti, 'wenquanyi micro hei', \5FAE\8F6F\96C5\9ED1, \5B8B\4F53, sans-serif;
}
b, strong {
font-weight: bold;
}
i, em {
font-style: normal;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
table th, table td {
border: 1px solid #ddd;
padding: 5px;
}
table th {
font-weight: inherit;
border-bottom-width: 2px;
border-bottom-color: #ccc;
}
img {
border: 0 none;
width: auto\9;
max-width: 100%;
vertical-align: top;
height: auto;
}
button, input, select, textarea {
font-family: inherit;
font-size: 100%;
margin: 0;
vertical-align: baseline;
}
button, html input[type="button"], input[type="reset"], input[type="submit"] {
-webkit-appearance: button;
cursor: pointer;
}
button[disabled], input[disabled] {
cursor: default;
}
input[type="checkbox"], input[type="radio"] {
box-sizing: border-box;
padding: 0;
}
input[type="search"] {
-webkit-appearance: textfield;
-moz-box-sizing: content-box;
-webkit-box-sizing: content-box;
box-sizing: content-box;
}
input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
input:focus {
outline: none;
}
select[size], select[multiple], select[size][multiple] {
border: 1px solid #AAA;
padding: 0;
}
article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section, summary {
display: block;
}
audio, canvas, video, progress {
display: inline-block;
}
body {
background: #fff;
}
input::-webkit-input-speech-button {
display: none
}
button, input, textarea {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
再次强调一下:·
需要根据你的设计稿的大小来调整脚本最后的两个参数。
})(750, 750);
第一个参数是设计稿的宽度,一般设计稿有640,或者是750,你可以根据实际调整
第二个参数则是设置制作稿的最大宽度,超过750,则以750为最大限制。
附阿里的flexible.js和flexible.css
flexible.js
;(function(win, lib) {
var doc = win.document;
var docEl = doc.documentElement;
var metaEl = doc.querySelector('meta[name="viewport"]');
var flexibleEl = doc.querySelector('meta[name="flexible"]');
var dpr = 0;
var scale = 0;
var tid;
var flexible = lib.flexible || (lib.flexible = {});
if (metaEl) {
console.warn('将根据已有的meta标签来设置缩放比例');
var match = metaEl.getAttribute('content').match(/initial\-scale=([\d\.]+)/);
if (match) {
scale = parseFloat(match[1]);
dpr = parseInt(1 / scale);
}
} else if (flexibleEl) {
var content = flexibleEl.getAttribute('content');
if (content) {
var initialDpr = content.match(/initial\-dpr=([\d\.]+)/);
var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/);
if (initialDpr) {
dpr = parseFloat(initialDpr[1]);
scale = parseFloat((1 / dpr).toFixed(2));
}
if (maximumDpr) {
dpr = parseFloat(maximumDpr[1]);
scale = parseFloat((1 / dpr).toFixed(2));
}
}
}
if (!dpr && !scale) {
var isAndroid = win.navigator.appVersion.match(/android/gi);
var isIPhone = win.navigator.appVersion.match(/iphone/gi);
var devicePixelRatio = win.devicePixelRatio;
if (isIPhone) {
// iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
dpr = 3;
} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
dpr = 2;
} else {
dpr = 1;
}
} else {
// 其他设备下,仍旧使用1倍的方案
dpr = 1;
}
scale = 1 / dpr;
}
docEl.setAttribute('data-dpr', dpr);
if (!metaEl) {
metaEl = doc.createElement('meta');
metaEl.setAttribute('name', 'viewport');
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
if (docEl.firstElementChild) {
docEl.firstElementChild.appendChild(metaEl);
} else {
var wrap = doc.createElement('div');
wrap.appendChild(metaEl);
doc.write(wrap.innerHTML);
}
}
function refreshRem(){
var width = docEl.getBoundingClientRect().width;
if (width / dpr > 540) {
width = 540 * dpr;
}
var rem = width / 10;
docEl.style.fontSize = rem + 'px';
flexible.rem = win.rem = rem;
}
win.addEventListener('resize', function() {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}, false);
win.addEventListener('pageshow', function(e) {
if (e.persisted) {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}
}, false);
if (doc.readyState === 'complete') {
doc.body.style.fontSize = 12 * dpr + 'px';
} else {
doc.addEventListener('DOMContentLoaded', function(e) {
doc.body.style.fontSize = 12 * dpr + 'px';
}, false);
}
refreshRem();
flexible.dpr = win.dpr = dpr;
flexible.refreshRem = refreshRem;
flexible.rem2px = function(d) {
var val = parseFloat(d) * this.rem;
if (typeof d === 'string' && d.match(/rem$/)) {
val += 'px';
}
return val;
}
flexible.px2rem = function(d) {
var val = parseFloat(d) / this.rem;
if (typeof d === 'string' && d.match(/px$/)) {
val += 'rem';
}
return val;
}
})(window, window['lib'] || (window['lib'] = {}));
flexible.css3
@charset "utf-8";
html {
color: #000;
background: #fff;
overflow-y: scroll;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%
}
html * {
outline: 0;
-webkit-text-size-adjust: none;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0)
}
html, body {
font-family: sans-serif
}
body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, code, form, fieldset, legend, input, textarea, p, blockquote, th, td, hr, button, article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {
margin: 0;
padding: 0
}
input, select, textarea {
font-size: 100%
}
table {
border-collapse: collapse;
border-spacing: 0
}
fieldset, img {
border: 0
}
abbr, acronym {
border: 0;
font-variant: normal
}
del {
text-decoration: line-through
}
address, caption, cite, code, dfn, em, th, var {
font-style: normal;
font-weight: 500
}
ol, ul {
list-style: none
}
caption, th {
text-align: left
}
h1, h2, h3, h4, h5, h6 {
font-size: 100%;
font-weight: 500
}
q:before, q:after {
content: ''
}
sub, sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline
}
sup {
top: -.5em
}
sub {
bottom: -.25em
}
a:hover {
text-decoration: underline
}
ins, a {
text-decoration: none
}