移动端(手机端)页面自适应解决方案—rem布局

移动端(手机端)页面自适应解决方案—rem布局

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

一、网易做法:

引入:页面开头处引入下面这段代码,用于动态计算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';
};

二、淘宝做法(推荐做法,尤其是app内嵌页面):

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

})(window, window[‘lib’] || (window[‘lib’] = {}));" title="" data-original-title=“已复制”>

;
(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 (<span class="hljs-name">metaEl</span>) {
    var match = metaEl.getAttribute(<span class="hljs-name">'content'</span>).match(/initial\-scale=([\d\.]+)/)<span class="hljs-comment">;</span>
    if (<span class="hljs-name">match</span>) {
        scale = parseFloat(<span class="hljs-name">match</span>[<span class="hljs-number">1</span>])<span class="hljs-comment">;</span>
        dpr = parseInt(<span class="hljs-number">1</span> / scale)<span class="hljs-comment">;</span>
    }
} else if (<span class="hljs-name">flexibleEl</span>) {
    var content = flexibleEl.getAttribute(<span class="hljs-name">'content'</span>)<span class="hljs-comment">;</span>
    if (<span class="hljs-name">content</span>) {
        var initialDpr = content.match(/initial\-dpr=([\d\.]+)/)<span class="hljs-comment">;</span>
        var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/)<span class="hljs-comment">;</span>
        if (<span class="hljs-name">initialDpr</span>) {
            dpr = parseFloat(<span class="hljs-name">initialDpr</span>[<span class="hljs-number">1</span>])<span class="hljs-comment">;</span>
            scale = parseFloat((<span class="hljs-number">1</span> / dpr).toFixed(<span class="hljs-number">2</span>))<span class="hljs-comment">;</span>
        }
        if (<span class="hljs-name">maximumDpr</span>) {
            dpr = parseFloat(<span class="hljs-name">maximumDpr</span>[<span class="hljs-number">1</span>])<span class="hljs-comment">;</span>
            scale = parseFloat((<span class="hljs-number">1</span> / dpr).toFixed(<span class="hljs-number">2</span>))<span class="hljs-comment">;</span>
        }
    }
}

if (<span class="hljs-name">!dpr</span> &amp;&amp; !scale) {
    var isAndroid = win.navigator.appVersion.match(/android/gi)<span class="hljs-comment">;</span>
    var isIPhone = win.navigator.appVersion.match(/iphone/gi)<span class="hljs-comment">;</span>
    var devicePixelRatio = win.devicePixelRatio;
    if (<span class="hljs-name">isIPhone</span>) {
        // iOS下,对于<span class="hljs-number">2</span>和<span class="hljs-number">3</span>的屏,用<span class="hljs-number">2</span>倍的方案,其余的用<span class="hljs-number">1</span>倍方案
        if (<span class="hljs-name">devicePixelRatio</span> &gt;= <span class="hljs-number">3</span> &amp;&amp; (<span class="hljs-name">!dpr</span> || dpr &gt;= <span class="hljs-number">3</span>)) {
            dpr = <span class="hljs-number">3</span><span class="hljs-comment">;</span>
        } else if (<span class="hljs-name">devicePixelRatio</span> &gt;= <span class="hljs-number">2</span> &amp;&amp; (<span class="hljs-name">!dpr</span> || dpr &gt;= <span class="hljs-number">2</span>)) {
            dpr = <span class="hljs-number">2</span><span class="hljs-comment">;</span>
        } else {
            dpr = <span class="hljs-number">1</span><span class="hljs-comment">;</span>
        }
    } else {
        // 其他设备下,仍旧使用<span class="hljs-number">1</span>倍的方案
        dpr = <span class="hljs-number">1</span><span class="hljs-comment">;</span>
    }
    scale = <span class="hljs-number">1</span> / dpr;
}

docEl.setAttribute(<span class="hljs-name">'data-dpr'</span>, dpr)<span class="hljs-comment">;</span>
if (<span class="hljs-name">!metaEl</span>) {
    metaEl = doc.createElement(<span class="hljs-name">'meta'</span>)<span class="hljs-comment">;</span>
    metaEl.setAttribute(<span class="hljs-name">'name'</span>, 'viewport')<span class="hljs-comment">;</span>
    metaEl.setAttribute(<span class="hljs-name">'content'</span>, 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no')<span class="hljs-comment">;</span>
    if (<span class="hljs-name">docEl.firstElementChild</span>) {
        docEl.firstElementChild.appendChild(<span class="hljs-name">metaEl</span>)<span class="hljs-comment">;</span>
    } else {
        var wrap = doc.createElement(<span class="hljs-name">'div'</span>)<span class="hljs-comment">;</span>
        wrap.appendChild(<span class="hljs-name">metaEl</span>)<span class="hljs-comment">;</span>
        doc.write(<span class="hljs-name">wrap.innerHTML</span>)<span class="hljs-comment">;</span>
    }
}

function refreshRem() {
    var width = docEl.getBoundingClientRect().width;
    // 适配平板
    if (<span class="hljs-name">width</span> / dpr &gt; <span class="hljs-number">540</span>) {
        width = <span class="hljs-number">540</span> * dpr;
    }
    var rem = width / <span class="hljs-number">10</span><span class="hljs-comment">;</span>
    docEl.style.fontSize = rem + 'px';
    flexible.rem = win.rem = rem;
}

win.addEventListener(<span class="hljs-name">'resize'</span>, function() {
    clearTimeout(<span class="hljs-name">tid</span>)<span class="hljs-comment">;</span>
    tid = setTimeout(<span class="hljs-name">refreshRem</span>, <span class="hljs-number">300</span>)<span class="hljs-comment">;</span>
}, <span class="hljs-literal">false</span>)<span class="hljs-comment">;</span>
win.addEventListener(<span class="hljs-name">'pageshow'</span>, function(<span class="hljs-name">e</span>) {
    if (<span class="hljs-name">e.persisted</span>) {
        clearTimeout(<span class="hljs-name">tid</span>)<span class="hljs-comment">;</span>
        tid = setTimeout(<span class="hljs-name">refreshRem</span>, <span class="hljs-number">300</span>)<span class="hljs-comment">;</span>
    }
}, <span class="hljs-literal">false</span>)<span class="hljs-comment">;</span>

if (<span class="hljs-name">doc.readyState</span> === 'complete') {
    doc.body.style.fontSize = <span class="hljs-number">12</span> * dpr + 'px';
} else {
    doc.addEventListener(<span class="hljs-name">'DOMContentLoaded'</span>, function(<span class="hljs-name">e</span>) {
        doc.body.style.fontSize = <span class="hljs-number">12</span> * dpr + 'px';
    }, <span class="hljs-literal">false</span>)<span class="hljs-comment">;</span>
}


refreshRem()<span class="hljs-comment">;</span>

flexible.dpr = win.dpr = dpr;
flexible.refreshRem = refreshRem;
flexible.rem2px = function(<span class="hljs-name">d</span>) {
    var val = parseFloat(<span class="hljs-name">d</span>) * this.rem;
    if (<span class="hljs-name">typeof</span> d === 'string' &amp;&amp; d.match(/rem$/)) {
        val += 'px';
    }
    return val;
}
flexible.px2rem = function(<span class="hljs-name">d</span>) {
    var val = parseFloat(<span class="hljs-name">d</span>) / this.rem;
    if (<span class="hljs-name">typeof</span> d === 'string' &amp;&amp; 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;
}

具体实现原理请参照:从网易与淘宝的font-size思考前端设计稿与工作流,写的很不错!

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

猜你喜欢

转载自blog.csdn.net/weixin_43844392/article/details/89880009