移动端适配--flexible.js
发布日期:2021-08-30 20:31:02 浏览次数:1 分类:技术文章

本文共 5182 字,大约阅读时间需要 17 分钟。

引言:

H5适配一直是一个比较普遍的问题,很多文章都会讲,最近开发了一个H5的项目使用了一下淘宝的 flexible.js,写一篇文章自己总结一下。

一、背景介绍:

Flexible.js是淘宝公开的一种移动端适配方案,用来解决H5开发中的各个机型适配问题,是一种比较成熟的适配方案。

二、使用方法:

在html头部引入flexible.js,最好放在最头部,重构时使用rem替代px像素即可,flexible会做好所有适配。换算关系为1rem对应1/10设计尺寸,如ipone6设计尺寸为750px,那么重构时宽度对应的就是10rem。

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

可以看出其核心就是两段代码:

1.当用户没有设置viewport的时候调整viewport:

metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');

viewport(视口)的调整逻辑是根据dpr(window.devicePixelRatio,设备像素比)来调整。

以iphone6为例:

dpr = 2,sale = 1/dpr = 0.5,也是就是说flexible会将视口缩放到原来的0.5倍,这样做的好处是能让逻辑像素与物理像素相等,避免出现1px在retina屏幕上显示过粗的现象(移动端经典的1px问题)。

2.设置根元素字体大小:

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

rem是根据根元素来做渲染的,所以flexible直接调整根元素的大小就可以做到适配了,调整的思路是根据视口宽度(document.doumentElement.getBoundingClientRect().width)做调整(ps:viewport还分layout viewport和 visual viewport,不引申)。

四、注意事项&&总结:

1.当用户不设置viewport的时候,flexible.js会根据dpr默认设置viewport,这里的好处已经讲到,在精准显示1px像素的时候比较准确。但是也会带来部分问题,如引用第三方插件并且插件本身用px像素设置,这个时候就会带来缩放显示问题,所以如果有这种需求的话建议自己权衡,个人建议可能使用第三方的业务自行设置viewport,1px问题可以用其他手段处理,一般没有高保真的需求本身也没有必要。

2.flexible对字体的设置不推荐使用rem单位,建议使用px像素,适配根据dpr来做。原因简单看了下主要是网页可能会使用点阵字体,一般点阵大小是16、24的,调整后的字体大小可能不大标准,在字体点阵上显示会比较模糊,不细究了,有时间再研究补充。

总结:移动端适配核心就是将像素rem化,之后根据视口调整根元素达到适配的效果。

转载于:https://www.cnblogs.com/DevinnZ/p/8683902.html

转载地址:https://blog.csdn.net/weixin_34050005/article/details/94032729 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:2014-12-27 迎接15年前夕,原来时间是这样过的
下一篇:邮票面值设计

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2024年04月10日 22时17分31秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章