media query ie8- 兼容实现总结

机构:上海非凡学院 时间:2015-11-28 点击:565

  下图为淘宝用户的屏幕分辨率和浏览器比例,鉴于ie8-浏览器目前占比约70%,media query的ie8-兼容迫于现实还是要做……

  media query简介

  miedia query有2种引入方式:

  1.link标签方式

  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.js和css3-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中所有的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 放到当前域服务器上

  这里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

  更多资讯访问上海网页设计培训学校

返回顶部