flexible.js 移动端自适应框架

来源:互联网 发布:linux patch 编辑:程序博客网 时间:2024/06/05 23:14
;(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;        //var isRegularDpr = devicePixelRatio.toString().match(/^[1-9]\d*$/g);        if (isIPhone) {            // 对于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');        //Android target-densitydpi=device-dpi        var attribute = 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no';        //判断是否是WebView        var app = getCookie('chelun_appName');        if(app) {            attribute = 'width=device-width,'+attribute;        }        metaEl.setAttribute('content', attribute);        if (docEl.firstElementChild) {            docEl.firstElementChild.appendChild(metaEl);        } else {            var wrap = doc.createElement('div');            wrap.appendChild(metaEl);            doc.write(wrap.innerHTML);        }    }    function getCookie(name){        var maps = {};        var cookArr = document.cookie.split(';')        for(var i in cookArr){            var tmp = cookArr[i].replace(/^\s*/, '');            if(tmp){                var nv = tmp.split('=');                maps[nv[0]] = nv[1] || '';            }        }        return maps[name];    }    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.js

这一步其实非常简单,只要把flexible.js的内容复制出来,在本地新建一个flexible.js的文件,打开粘贴进去就可以了,我把这个文件放在了js/lib下面:

接着在html页面里面,尽可能早的引入这个js文件(为了让适配的效果更快):

注:使用lib-flexible,通常不要写:

复制代码代码如下:
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"/>

交给flexible.js自动处理。

然后在chrome的模拟器里面,选择iphone6,应该就能看到html的font-size已经被设置为font-size: 75px了:

3. 编写CSS
基本要求:

1)除font-size外,其它大小都根据750标注稿的尺寸,转换成rem单位的值,转换方法为:标注稿尺寸 / 标注稿基准字体大小;

2)标注稿基准字体大小 = 标注稿宽度 / 10,如标注稿宽为750,标注稿基准字体大小为75;标注稿宽为640,标注稿基准字体大小为64;(所以淘宝这个方案是可以在任意设计稿尺寸下使用的)

3)如果需要设置font-size,可跟据html的data-dpr属性来处理,类似下面的写法:

?
1
2
3
4
5
6
7
[data-dpr="2"] p {
  font-size: 16px;
}
 
[data-dpr="3"] p {
  font-size: 24px;
}

以安卓下载按钮的样式为例,说明这种用法。android.png的尺寸为:414*80,所以css这么写:

?
1
2
3
4
.btn {
  width: 414rem/@font-size-base;
  height: 80rem/@font-size-base;
}

由于用了less,事先定义了一个变量来保存标注稿基准字体大小:

@font-size-base: 75;
所以px2rem的转换变得非常容易,如上所示。less编译之后,会将正确的rem值计算出来:

?
1
2
3
4
.btn {
 width: 5.52rem;
 height: 1.06666667rem;
}

到此,lib-flexible的基本实践就结束了,不过还有一个问题,就是retina屏的问题,到现在都还没提到@3x下图的那些切图怎么办,其实很简单,借助html元素的data-dpr属性,可以轻松实现另一种媒介查询,以便在devicePixelRatio>=2的时候启用@3x下的图片,还是以安卓下载按钮的样式为例,写法是:

?
1
2
3
4
5
6
.btn-android {
 background-image: url("../img/@2x/android.png?v=@@version");
 [data-dpr="3"] & {
  background-image: url("../img/@3x/android.png?v=@@version");
 }
}

这下就OK了,原先还不知道data-dpr有什么作用,现在看看,作用还是挺大的。

注:

  • 1) 由于使用了grunt构建,所以需要先安装node ,git,再通过npm安装grunt 和bower
  • 2)考虑到将来可能要做全屏滚动的效果,所以这页面一开始就是用fullpage.js来做的,通过bower引入了jquery跟fullpage.js的库
  • 3) 模块化用到了requirejs
  • 4)运行grunt default完成构建,再运行grunt server启动静态服务器预览。

以上就是实现淘宝弹性布局方案lib-flexible实践的全部过程,希望对大家的学习有所启发。

0 0
原创粉丝点击