Respond.js让IE6-8支持CSS3 Media Query

Bootstrap里面就引入了这个js文件,从名字看出来是自适应的兼容。打开IE看了一下,效果挺好的,自适应的效果挺好的。Respond.js让不支持CSS3 Media Query的浏览器包括IE6-IE8等其余浏览器支持查询。php

使用方式
官方demo地址: http://scottjehl.github.com/Respond/test/test.html
1.在css中正经常使用 min/max-width media queries
@media screen and (min-width: 480px){
        ...styles for 480px and up go here
    }

2.引入respond.min.js,但要在css的后面(越早引入越好,在ie下面看到页面闪屏的几率就越低,由于最初css会先渲染出来,如 果respond.js加载得很后面,这时从新根据media query解析出来的css会再改变一次页面的布局等,因此看起来有闪屏的现象)css

实现思路

  • 1.把head中全部<link rel=“sheetstyle” href=“xx”/>的css路径取出来放入数组
  • 2.而后遍历数组一个个发ajax请求
  • 3.ajax回调后仅分析response中的media query的min-width和max-width语法,分析出viewport变化区间对应相应的css块
  • 4.页面初始化时和window.resize时,根据当前viewport使用相应的css块。
//检测是否支持media query,检测css是否有效的方法都差很少,建立一个元素应用该css后检测元素宽度,而后清除该元素。
window.matchMedia = window.matchMedia || (function(doc, undefined){
  var bool,
      docElem  = doc.documentElement,
      refNode  = docElem.firstElementChild || docElem.firstChild,
      // fakeBody required for 
      fakeBody = doc.createElement('body'),
      div      = doc.createElement('div');
  div.id = 'mq-test-1';
  div.style.cssText = "position:absolute;top:-100em";
  fakeBody.style.background = "none";
  fakeBody.appendChild(div);
  return function(q){
    div.innerHTML = '­';
    docElem.insertBefore(fakeBody, refNode);
    bool = div.offsetWidth == 42;
    docElem.removeChild(fakeBody);
    return { matches: bool, media: q };
  };
})(document);
		.......
if( !!href && isCSS && !parsedSheets[ href ] ){
    // selectivizr exposes css through the rawCssText expando
    if (sheet.styleSheet && sheet.styleSheet.rawCssText) {
                //sheet.styleSheet.rawCssText看不懂,原来是方便selectivizr和respond.js联用,http://selectivizr.com/tests/respond/
                //selectivizr的做用是 CSS3 selectors for IE;约定将原csstext放在styleSheet的link上的扩展属性rawCssText上;这里若是联用selectivizr能够少次ajax请求
        translate( sheet.styleSheet.rawCssText, href, media );
        parsedSheets[ href ] = true;
    } else {
        if( (!/^([a-zA-Z:]*//)/.test( href ) && !base)
            || href.replace( RegExp.$1, "" ).split( "/" )[0] === win.location.host ){
            requestQueue.push( {
                href: href,
                media: media
            } );
        }
    }
}
.......

其他的代码就 是ajax实现和translate media query的max-width min-width的逻辑了;能够看出这里必须依赖ajax请求css路径才能获得css文件中的mediaquery的内容,那ajax的跨域问题就要 解决了;因为咱们的静态资源都是要放cdn的,respond.js也给出了跨域方法,即引入代理页面。html

		//把cross-domain/respond-proxy.html 放到cdn上 //把cross-domain/respond.proxy.gif 放到当前域服务器上 <!-- Respond.js proxy on external server --> <link href="http://externalcdn.com/respond-proxy.html" id="respond-proxy" rel="respond-proxy" /> <!-- Respond.js redirect location on local server --> <link href="/path/to/respond.proxy.gif" id="respond-redirect" rel="respond-redirect" /> <!-- Respond.js proxy script on local server --> <script src="/path/to/respond.proxy.js"></script>

这里ajax跨域实现是经过代理页面将获取到的css,再经过window.name通讯实现;如在respond.proxy.js中git

function checkFrameName() {
    var cssText;
    try {
        cssText = iframe.contentWindow.name;
                var now = new Date().getTime(),useTime = now - initTime;
        alert('获取css耗时:'+ useTime + 'ms');
    }
    catch (e) { }

    if (cssText) {
        ……//销毁以前用于通讯的iframe,后续回调callback
        callback(cssText);
    }
    else{
        win.setTimeout(checkFrameName, 100);
    }
}
win.setTimeout(checkFrameName, 500);//500ms后确认内部iframe的name值是否传递过来,后续再更新当前viewport该用的css。

由于实现跨域代理的问题,初始化页面时应用上所有css耗时较长,如下光测试从开始执行该js文件到css取回调用以前的耗时为500ms-515ms之间(每次刷新结果不同),ie8下测试结果以下 T10Xg1Xl0cXXXxfAUk-634-396github

测试结果发现,刷新页面后会有明显的闪屏(以该测试demo为例,一开始页面背景是黑色的,这是默认css中的,跨域js执行完成后分析出 media query中的该viewport尺寸下应该应用red的背景,因此又变成红色),间隔时间为500ms以上。因此体验不是很好,并且该场景中ajax跨 域目前已经没有更好的实现方式,500ms间隔的闪屏避免不了。ajax

同时由于是ajax请求css,因此会由于响应式而额外产生一个请求,好在以前css请求过一遍,此次ajax请求是读取浏览器缓存中的,以下图中fiddler的检测结果中的第三个请求和第六个请求: T1IHM0XaleXXaqU36o-600-217跨域

respond.js总结

  • 优势:压缩后仅1k,不跨域时性能ok,只需引入respond.js通用易用
  • 缺点:仅支持media query的min-width和max-width(用于响应式够用);支持跨域,虽然配置有点麻烦,实现跨域代价高并且有闪屏体验欠佳。
相关文章
相关标签/搜索