1 Star 14 Fork 2

Vincent / notes

 / 详情

Rem自适应js---flexible.min.js

待办的
拥有者
创建于  
2018-08-24 14:24

由于移动端特殊性,本文讲的是如何使用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元素来解决!
如下:

<style id="rootFontSize">html{font-size: 100px !important;}</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
}

评论 (0)

Vincent 创建了任务
Vincent 更新了任务
Vincent 更新了任务

登录 后才可以发表评论

状态
负责人
里程碑
Pull Requests
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
开始日期   -   截止日期
-
置顶选项
优先级
参与者(1)
1264309 vincentyun 1578947683
1
https://gitee.com/vincentyun/jsnote.git
git@gitee.com:vincentyun/jsnote.git
vincentyun
jsnote
notes

搜索帮助