虽然说响应式设计的理想状态是,需对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的重复维护的问题。

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

  1. HTML-HTML5+CSS3权威指南阅读(二、让IE支持HTML5标签及对CSS3 Media Query的兼容)

    兼容解决 HTML5是在低版本的浏览器(IE8-)的兼容是有限的,类似很多结构性的标 签<header>.<section>.<footer>等在IE8以下不会被识 ...

  2. media query学习笔记

    原文转自:http://blog.csdn.net/renfufei/article/details/19981133 http://www.cnblogs.com/softlover/archive ...

  3. (转载)IE8+兼容经验小结

    本文分享下我在项目中积累的IE8+兼容性问题的解决方法.根据我的实践经验,如果你在写HTML/CSS时候是按照W3C推荐的方式写的,然后下面的几点都关注过,那么基本上很大一部分IE8+兼容性问题都OK ...

  4. [转载] IE8+兼容小结

    本文分享下我在项目中积累的IE8+兼容性问题的解决方法.根据我的实践经验,如果你在写HTML/CSS时候是按照W3C推荐的方式写的,然后下面的几点都关注过,那么基本上很大一部分IE8+兼容性问题都OK ...

  5. CSS3 之媒体查询Media Query

    Media Queries是CSS3有关媒体查询的属性,有了CSS3 之媒体查询Media Queries就可以进行媒体查询,针对每个不同的媒体进行不同的样式编写.传说中的Web响应式布局就可以毫无压 ...

  6. 关于IE8下media query兼容的解决方案探讨

    在国内IE8至少还占有20%的市场份额,所以在做网站时,必须得为这部分用户特殊兼容考虑. 一方面IE8上面很多css3定义的标签不能使用,另外一方面javascript的addEventListene ...

  7. 一种让 IE6/7/8 支持 media query 响应式设计的方法

    在不同的浏览器宽度下使用不同的 CSS 声明,常见的方案是使用 media query,但这个方案不支持 IE9 以下浏览器. 国外比较流行的 UI 框架 bootstrap v3 版本中使用 med ...

  8. IE8+兼容经验小结

    最近一段时间,我都使用Flask+Bootstrap3的框架组合进行开发.本文就是在这种技术组合下,分享IE8+兼容性问题的解决方法.根据我的实践经验,如果你在写HTML/CSS时候是按照W3C推荐的 ...

  9. [转]CSS3 Media Query实现响应布局

    讲到响应式布局, 相信大家都有一定的了解,响应式布局是今年很流行的一个设计理念,随着移动互联网的盛行,为解决如今各式各样的浏览器分辨率以及不同移动设备的显示效果, 设计师提出了响应式布局的设计方案.今 ...

随机推荐

  1. C堆栈

    C堆栈实现的表达式求值 //Luangeng #include<stdio.h> #include<conio.h> #include<windows.h> #de ...

  2. HTML5/CSS3(PrefixFree.js) 3D文字特效

    之前在园子里看到一个HTML5/CSS3的文字特效(这里),觉得挺好玩的所以小小的研究了下,不过发现代码都是针对webkit以及FF的所以IE跪了. Runjs 我将示例中的代码进行了精简,后来发现C ...

  3. Java CSV操作(导出和导入)

    Java CSV操作(导出和导入)  CSV是逗号分隔文件(Comma Separated Values)的首字母英文缩写,是一种用来存储数据的纯文本格式,通常用于电子表格或数据库软件.在 CSV文件 ...

  4. sql 集合运算

    UNION 并运算 UNION 操作符用于合并两个或多个 SELECT 语句的结果集. 请注意,UNION 内部的 SELECT 语句必须拥有相同数量的列.列也必须拥有相似的数据类型.同时,每条 SE ...

  5. UVA 437 十九 The Tower of Babylon

    The Tower of Babylon Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Subm ...

  6. [HDOJ3714]Error Curves(三分)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3714 题意:求n个二次函数在[0,1000]的最小值. 三分枚举. #include <bits ...

  7. Beaglebone Black 和树莓派

    我不是创客.我买了个 Beaglebone Black 来玩,主要是拿来学习. 入手前,看过好几个树莓派 (Raspi - 2 Model B)和 Beaglebone Black (BBB) 比较, ...

  8. sequenza细胞纯度计算

    安装sequenza bam文件要放在前面,否侧会-f命令可能识别错误 samtools mpileup a.bam -f hg19.fasta -Q 20 |gzip > normal.pil ...

  9. Metasploit中使用Nessus插件命令

    基本命令 导入扫描结果 db_import  /路径/文件.nessus 查看数据库里面现有的IP信息 msf > db_hosts -c address,svcs,vulns(注:vulns是 ...

  10. lotus 公式

    函数 描述@UserName 返回用户名或服务器名.@Name([key]; name) 更改用户名的格式.关键字包含 [CN] 以从一个专有名字中解析出公共名,[Abbreviate] 缩写规范格式 ...