专栏首页张培跃移动端页面自适应解决方案:rem 布局篇

移动端页面自适应解决方案:rem 布局篇

移动端rem自适应方案

假设设计妹妹给我们的设计稿尺寸为750 * 1340。结合网易、淘宝移动端首页html元素上的font-size属性,html5设计稿尺寸以及前端与设计之间协作流程一般分为下面两种。

一、网易做法

引入:页面开头处引入下面这段代码,用于动态计算font-size

(function(doc, win) {
    var docEl = doc.documentElement,
        isIOS = navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/),
        dpr = isIOS ? Math.min(win.devicePixelRatio, 3) : 1,
        dpr = window.top === window.self ? dpr : 1, //被iframe引用时,禁止缩放
        dpr = 1,
        scale = 1 / dpr,
        resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize';
    docEl.dataset.dpr = dpr;
    var metaEl = doc.createElement('meta');
    metaEl.name = 'viewport';
    metaEl.content = 'initial-scale=' + scale + ',maximum-scale=' + scale + ', minimum-scale=' + scale;
    docEl.firstElementChild.appendChild(metaEl);
    var recalc = function() {
        var width = docEl.clientWidth;
        if (width / dpr > 750) {
            width = 750 * dpr;
        }
        // 乘以100,px : rem = 100 : 1
        docEl.style.fontSize = 100 * (width / 750) + 'px';
    };
    recalc()
    if (!doc.addEventListener) return;
    win.addEventListener(resizeEvt, recalc, false);
})(document, window);

使用:

未引入前

body {
    width: 750px;
    height: 640px;
}

引入后:除以100并将px换成rem

body {
    width: 7.5rem;
    height: 6.4rem;
}

换算的依据:

// 乘以100,px : rem = 100 : 1
var recalc = function() {
    var width = docEl.clientWidth;
    if (width / dpr > 750) {
        width = 750 * dpr;
    }
    // 乘以100,px : rem = 100 : 1
    docEl.style.fontSize = 100 * (width / 750) + 'px';
};

二、淘宝做法

引入:页面开头处引入下面这段代码,用于动态计算font-size,或者单独放入一个文件,引入文件也可以

;
(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) {
        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'] = {}));

使用:

未引入前

body {
    width: 750px;
    height: 640px;
}

引入后

@font-size-base: 75;
body {
    width: 750rem/@font-size-base;
    height: 640rem/@font-size-base;
}

换算依据:

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;
}

这边是用的less,如果您没有用less,就需要手动计算,当然也可以转化为px : rem = 100 : 1。 如果想转化为px : rem = 100 : 1,可以修改上面的refreshRem函数:

function refreshRem() {
    var width = docEl.getBoundingClientRect().width
    // 适配平板
    if (width / dpr > 750) {
      width = 750 * dpr
    }
    var rem = 100 * (width / 750)
    docEl.style.fontSize = rem + 'px'
    flexible.rem = win.rem = rem;
}

使用:

未引入前

body {
    width: 750px;
    height: 640px;
}

引入后:除以100并将px换成rem

body {
    width: 7.5rem;
    height: 6.4rem;
}

换算依据就是上面修改的代码:

function refreshRem() {
    var width = docEl.getBoundingClientRect().width
    // 适配平板
    if (width / dpr > 750) {
      width = 750 * dpr
    }
    var rem = 100 * (width / 750)
    docEl.style.fontSize = rem + 'px'
    flexible.rem = win.rem = rem;
}

希望对需要的朋友有所帮助!

源自:segmentfault

声明:文章著作权归作者所有,如有侵权,请联系小编删除。

本文分享自微信公众号 - 张培跃(zhangpeiyue8)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-06-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 真正掌握vuex的使用方法(三)

    目前当前的票数已经可以在页面中渲染出来了!接下来要做的事就是让按钮起到应有的责任:点击对应的按钮让数字加1, 总票数也要加1。很简单,只要给按钮增加一个事件,直...

    用户1272076
  • 原生态纯JavaScript 100大技巧大收集---你值得拥有(1--50)

    21、原生JavaScript中有insertBefore方法,可惜却没有insertAfter方法?用如下函数实现

    用户1272076
  • 真正掌握vuex的使用方法(一)

    咱们知道,vue项目当中的父子组件的交互是单通道传递,父组件通过props向子组件传递参数,而在子组件当中不不能直接修改接收的参数,而是需要通过自定义事件的方式...

    用户1272076
  • css显示模式

    其特点: div和span有什么区别? div会单独的占领一行,而span不会单独占领一行 div是一个容器级的标签, 而span是一个文本级的标签 容...

    用户7873631
  • css中元素的变化

    核心在于:块级标签可以嵌套任何的标签,文本级别的只能嵌套图片超链接 文字。 块级占一行,文本级不会。

    用户7873631
  • Qt 自定义 滚动条 样式

    http://www.cnblogs.com/xufeiyang/p/3314955.html

    bear_fish
  • 前端学习(16)~css3属性学习(十)

    text-shadow 可以设置多个阴影,每个阴影之间使用逗号隔开。我们来看个例子。

    Vincent-yuan
  • jquery封装的时间轴

    很多时候,都会用到类似于时间轴的东西,鉴于网络资源没有那么顺手,就想着自己搞一个,在此将源码贴出来。

    lzugis
  • EMLOG自适应emMsg提示信息

    Youngxj
  • CSS制作可爱的小猪,祝大家2019“猪”事顺心

    时间过得真快,2019年也是说来就来,时间是真的不等人啊。新的一年小伙伴们都有什么目标呢?赶紧向着目标努力吧,2020也会眨眼即到。

    Javanx

扫码关注云+社区

领取腾讯云代金券