media query ie8- 兼容实现总结

虽然说响应式设计的理想状态是,需对pc/移动各种终端进行响应;但是现实是高分辨率的pc端与手机终端屏幕相差太大,像电商这样有大量图片和文字信息的同时排版要求精准的页面,设计一个同时适应高分辨率pc又适合小尺寸的手机终端是挑战 ;同时高分辨率下pc页面信息量巨大,对于手机端用户是否需要,也许会造成带宽浪费;再者手机终端和pc终端的用户操作习惯也相差甚大,这种多图多信息量要求精准的页面,设计出来恐怕会是2个完全不同的版本,也许各自维护更方便。由于业务形态原因,随着用户分辨率的提高,1024x768已不再是主流,宽屏用户比例越来越大,因此我们的响应式考虑如何充分利用PC用户设备上更多空间而设计。下图为淘宝用户的屏幕分辨率和浏览器比例,鉴于ie8-浏览器目前占比约70%,media query的ie8-兼容迫于现实还是要做……

media query简介

miedia query有2种引入方式:

1.link标签方式

	
<link rel="stylesheet" type="text/css" media="screen" href="sans-serif.css">
<link rel="stylesheet" type="text/css" media="print" href="serif.css">

2.css方式

	@media screen {
  * { font-family: sans-serif }
}

媒体类型有很多种:‘aural’, ‘braille’, ‘handheld’, ‘print’, ‘projection’, ‘screen’, ‘tty’, ‘tv’、‘embossed’、 ‘speech’、‘3d-glasses‘,但最常用的是screen和print,对于前端们来讲最常用的应该只有screen了。应用于所有媒体类型可以用all,省略不写默认就是all。media query支持很多表达式,常用的如下,完整的查看这里

	
@media all and (min-width: 400px) and (max-width: 700px) { /*屏幕宽度在[400px,700]之间时,应用该css*/ }
@media all and (orientation: portrait) {  /*设备竖屏时*/  }
@media and (min-device-width: 800px) { /*最小设备宽度为800px时*/ }

利用media query可以轻松实现不同屏幕宽度时切换不同的页面布局,但是很不幸ie8及以下都还不支持media query,于是开始了下面的media query兼容之旅…… 目前实现media query ie兼容的库比较成熟的有respond.jscss3-mediaqueries-js它们各有优劣,respond.js压缩后1k,只实现了media query中最常用的min-width max-width的兼容;css3-mediaqueries-js基本实现了所有css3规范中的media query特性的兼容,所以导致压缩有16k,测试反馈其性能远低于respond.js;不过确实一淘首页2次响应式设计均只需用到max-width和min-width,Modernizr 和 H5BP 也均推荐使用respond.js,下面具体看看它们的实现吧

respond.js源码分析

使用方式

官方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会再改变一次页面的布局等,所以看起来有闪屏的现象)

实现思路

  • 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也给出了跨域方法,即引入代理页面。

		
//把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中

		
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下测试结果如下 

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

同时因为是ajax请求css,所以会因为响应式而额外产生一个请求,好在之前css请求过一遍,这次ajax请求是读取浏览器缓存中的,如下图中fiddler的检测结果中的第三个请求和第六个请求: 

respond.js总结

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

css3-mediaqueries-js源码分析

css3-mediaqueries-js官方文档和demo都没有,相对于respond.js css3-mediaqueries-js支持几乎所有的media query的语法,访问测试demo

实现逻辑

其实现逻辑和respond.js差不多,只是更加支持的media query更加全面,同时支持内联style,支持各种宽度单位(em|ex|px|in|cm|mm|pt|pc),但是这里的初始化是在domready后执行,为了让用户感觉不出页面有闪屏(之前应用初始化样式然后js提取media query中的样式再覆盖一遍)现象,这里的实现是先将html移出可视区域外,等解析完media query后再重置回来,但实际目测感觉稍有闪屏(当然这里的测试是测试body背景色,移出可视区域外不管用,当然绝大部分响应式场景是适用的),实现如下:

		
// prevent jumping of layout by hiding everything before painting <body> 先将html移出可视区域外
var docEl = document.documentElement;
    docEl.style.marginLeft = ‘-32767px‘;

// make sure it comes back after a while 异常处理,万一获取mediaquery css失败,重置回来
setTimeout(function () {
  docEl.style.marginTop = ‘‘;
}, 20000);

……

// return visibility after media queries are tested 生效后重新可见
cssHelper.addListener(‘cssMediaQueriesTested‘, function () {
    // force repaint in IE by changing width
    if (ua.ie) {
        docEl.style.width = ‘1px‘;
    }
    setTimeout(function () {
        docEl.style.width = ‘‘; // undo width
        docEl.style.marginLeft = ‘‘; // undo hide
        var now = new Date().getTime();
        var useTime = now - initTime;
        alert(‘media query生效时间:‘+useTime+‘ms‘);
    }, 0);
    // remove this listener to prevent following execution
    cssHelper.removeListener(‘cssMediaQueriesTested‘, arguments.callee);
});

其余实现和respond.js基本一致,也需要使用ajax,所以css3-media-queries.js本身不支持跨域,当然非要支持跨域也可以,也可以像respond.js一样使用代理页面跨域即可,但也会出现闪屏的现象。还是先看看不跨域情况下,大多数人为什么选择respond.js,主要原因还是完美支持的media query特性导致压缩后16K,下载和执行时间都逊于respond.js,下面是同域下在ie8的测试结果(耗时140ms而respond.js仅15ms):  

css3-mediaqueries-js总结

  • 优点:1、基本支持所有css3中的media query语法
  • 缺点:1、不支持跨域(如cdn),就算支持了跨域也存在闪屏现象;2、和respond.js对比性能较差

全局切换class

因为css/js需要放到cdn上面,需要跨域,css3-mediaqueries-js不支持跨域,respond.js支持跨域但是实现跨域后性能较差,有闪屏体验也差,而且配置麻烦,不方便各个业务通用。对比respond.js和css3-mediaqueries-js可知,实现响应式应用min-width和max-width足矣;同时模拟media query的效果只需要在2个关键时间点根据viewport切换css(初始化页面时和window.resize)即可。所以可以选择切换css link,可以动态切换css块,也可以切换class

  • 切换css link(优点:逻辑清晰;缺点:增加请求数,维护麻烦,如修改一个模块涉及到3个尺寸的响应,至少需要改3个文件)
		
<link rel="stylesheet" type="text/css" media="screen and (max-width: 990px)" href="respond750.css&uuot;>
<link rel="stylesheet" type="text/css" media="screen and (max-width: 1200px)" href="respond990.css">
  • 切换内联css块(respond.js和css3-mediaqueries-js就是通过js分析出media query然后自动根据当前viewport切换css块,这个理想环境下是最好的,自动分析只管写media query,但是依赖ajax获取css内容,跨域实现成本高体验也不好)
  • 全局切换class(特别是初始化页面时最好在页面内容未开始渲染之前切换class,不然会出现像韩国naver购物频道在宽屏时刷新效果,刷新时内容由中间向外偏),特定viewport用特殊全局class标记,响应式样式继承在该class下,实现大致如下:

实现方式

<head>
<style>
@media screen and (min-width: 990px) {
   .content {
      width: 990px;
      color: red;
   }
}
@media screen and (min-width: 1200px) {
   .content {
      width: 1200px;
      color: green;
   }
}
.w990 .content {
  width: 990px;
  color: red;
}
.w1200 .content {
  width: 1200px;
  color: green;
}
</style>
</head>
<body class="w990">
<!--[if lte IE 8]>
    <script>(function(){
    //为了不出现闪屏,在body下直接切换全局class,window.resize可以在domready后切换
    var D=KISSY.DOM,w=D.viewportWidth(),b=document.body;
    if(w<1200){D.addClass(b,"w990")} else {D.addClass(b,"w1200")}
    })();</script>
<![endif]-->
<div class="content">content</div>
</body>

全局切换class这种方式维护也是个问题,首先是js分散2处,body最上方切换全局class,domready时window.resize时切换class,同时响应式尺寸增加时,需要改变js判断条件;再看css的维护,media query一份,加全局class一份相同的,维护需要同时修改2次,初期media query几十行也能接受,但是后来改版media query几百行,这样维护成本就大大增加了,全局class和media query copy相同的代码引入less解决,使用方法如下:

		
#channels {
  .w1200() {
    .etao-channels {
      padding: 170px 0 0 30px;

      li {
        margin-right: 25px;
      }
    }
  }
  .w990() {
    .etao-channels {
      padding: 25px 0 0 15px;

      li {
        margin-right: 8px;
      }
    }
  .w750() {
    .etao-channels {
      padding: 5px 0 0 5px;

      li {
        margin-right: 5px;
      }
      a {
        color: #333;
      }
    }
  }
}
// 这样只需维护上面一处代码即可
#channels > .w1200;
@media (max-width: 1119px) {
  #channels > .w990;
}
@media (max-width: 989px) {
  #channels > .w750;
}
.w990 {
  #channels > .w990;
}
.w750 {
  #channels > .w750;
}

目前一淘新首页采用以上方法维护,支持1200px、990px、750px三个尺寸的响应,不得不承认维护成本还是偏高,欢迎各种改进建议

结束语

实现media query i8-兼容,respond.js在不跨域的情况下推荐使用(只有1k且不出现闪屏,使用方便,但会多一个ajax 304请求),但是跨域时(css/js在cdn)不推荐(会出现至少500ms间隔的闪屏,且需要在cdn上引入代理页面实现跨域);css3-mediaqueries-js不推荐使用,其更多是mediaqueries的完全兼容实现,但min-width和max-width即可满足响应式实现的要求。基于以上,我们采用全局切换class的方式实现ie8-的兼容,引入less解决media query 和 兼容css的重复维护的问题。

时间: 2024-11-08 11:45:43

media query ie8- 兼容实现总结的相关文章

media query学习笔记

原文转自:http://blog.csdn.net/renfufei/article/details/19981133 http://www.cnblogs.com/softlover/archive/2012/11/25/2787429.html  http://www.blueidea.com/tech/web/2010/7912_3.asp http://www.moke8.com/article-5657-1.html 一.基本定义 1.CSS中的Media Query(媒介查询)是什么

Css3的Media Query 媒体查询 方法总结—让您的网站兼容手机

最近几年,大屏幕手机和ipad等移动设备的流行,使你的网页兼容移动设备已成为一种流行!移动设备的屏幕大小是五花八门,各式各样!要想很好的兼容移动设备,Css3的media技术是功不可没. 我的博客,应用了CSS3的media技术,使其在手机等移动设备上面也可以查看.当然,只凭css3的media技术,做好手机网站是远远不够的,手机网站注意事项和总结,后面会陆续出一些文章,欢迎持续关注! 好了,废话少说,下面进入正题: 一.Css3的Media Queries 翻译成中文是“媒体查询”,有如下几种

IE8以下不支持css3 media query的解决办法

针对IE8以下不支持css3的media query,可以使用response.js解决 下载地址:https://github.com/scottjehl/Respond/ 这里有一篇关于其实现原理的文章:http://caibaojian.com/respondjs.html 引用时的注意点: 不可将媒介查询代码写在html内部,因为response是通过ajax分析link引入的css文件,故html里面的样式将被忽略. 引入文件需在css引入之后 <!--[if lte IE 8]>

Css3的Media Query方法总结—让您的网站兼容手机

一.Css3的Media Queries 翻译成中文是“媒体查询”,有如下几种引入方式: 1.直接head中引用,其实media在css2中已经存在,不过,他的主要作用您没有关注,兼容所有媒体等.你肯定见到过如下的写法: <link href="css/style.css" rel="stylesheet" type="text/css" media="all" /> 现在,我们为了兼容屏幕的大小,可以这么写: &

IE8+兼容经验小结

最近一段时间,我都使用Flask+Bootstrap3的框架组合进行开发.本文就是在这种技术组合下,分享IE8+兼容性问题的解决方法.根据我的实践经验,如果你在写HTML/CSS时候是按照W3C推荐的方式写的,然后下面的几点都关注过,那么基本上很大一部分IE8+兼容性问题都OK了(这里的IE8+主要是指IE8,据个人目测,IE9+的渲染效果已经非常好了). 前期准备 测试IE兼容性必须要在Windows中测,而且是Win7+,因为WinXP最高只支持IE8,IE9就呵呵啦!大部分做Web的童鞋都

CSS3 Media Query实现响应式Web设计(针对不同移动设备宽度)

如今的屏幕分辨率,小至320px(iPhone),大到2560px甚至更高(大显示器),变化范围极大.除了使用传统的台式机,用户会越来越多的通过手机.上网本.iPad一类的平板设备来浏览页面.这种情况下,固定宽度的设计方案将会显得越发不合理.页面需要有更好的适应性,其布局结构要做到根据不同的设备及屏幕分辨率进行响应调整.接下来,我们将了解一下怎样通过HTML5和CSS3 Media Queries(媒介查询)相关技术来实现跨设备跨浏览器的响应式Web设计方案 范例效果预览 首先,我们来看看本篇范

响应式设计的思考:媒体查询(media query)

Jason Grigsby发表了篇文章,<CSS Media Query for Mobile is Fool’s Gold>对媒体查询(media query)吐槽,大意是在移动设备上使用媒体查询会造成很多资源的浪费——浏览器请求到很多用不到的图片等资源,然后写了一些测试用例测试一些可用方法.然后Tim Kadlec写了篇<Media Query & Asset Downloading Results>,用js自动化的测试了Jason Grigsby的用例. 本文主要整理

CSS3 Media Query实现响应Web设计(宽度为不同的移动设备)

现在的屏幕分辨率.小到320px(iPhone),大到2560px或甚至更高(大显示屏).范围内变化很大.除了使用传统的台式机.用户会越来越多的通过手机.上网本.iPad一类的平板设备来浏览页面. 这样的情况下,固定宽度的设计方案将会显得越发不合理.页面须要有更好的适应性,其布局结构要做到依据不同的设备及屏幕分辨率进行响应调整.接下来,我们将了解一下如何通过HTML5和CSS3 Media Queries(媒介查询)相关技术来实现跨设备跨浏览器的响应式Web设计方案 范例效果预览 首先,我们来看

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

Bootstrap里面就引入了这个js文件,从名字看出来是自适应的兼容.打开IE看了一下,效果挺好的,自适应的效果挺好的.Respond.js让不支持CSS3 Media Query的浏览器包括IE6-IE8等其他浏览器支持查询. 使用方式 官方demo地址:http://scottjehl.github.com/Respond/test/test.html 1.在css中正常用 min/max-width media queries @media screen and (min-width: