Media Queries之Respond.js
一、stackoverflow上面对css3-mediaqueries.js与respond.js的比较
css3-mediaqueries.js
Pros
Supports min, max and min+max mediaqueries
Supports px and em values
Reacts on window resize
Elaborates on-page CSS (style tag) and external stylesheets
Cons
Doesn't support width mediaquery
Doesn't elaborate link[media="screen and ..."] nor @imported stylesheet
respond.js
Pros
Supports min, max and min+max mediaqueries
Supports px and em values
Reacts on window resize
Elaborates external stylesheets only
Cons
Doesn't support width mediaquery
Doesn't elaborate on-page CSS, link [media="screen and ..."] nor @imported stylesheets
It may cause a javascript error when combined with jQuery on load events, to solve it you need to place the script at the end of the page
二、Respond.js源码分析
https://github.com/scottjehl/Respond
A fast & lightweight polyfill for min/max-width CSS3 Media Queries (for IE 6-8, and more)
Respond.js应用的例子,参考http://skinnyties.com
查看skinnyties.com源代码,可以看到
可以在GitHub上可以下载它的未压缩版本respond.src.js(或者将min文件format,不推荐,因为JS压缩后的变量名都是处理过的,不方便阅读),本文使用Fiddler进行本地重定向,分析源码。
1.监听resize事件,以达到改变窗口大小实时响应
function callMedia(){
applyMedia( true );
}
if( win.addEventListener ){
// 标准2级DOM事件模型
win.addEventListener( "resize", callMedia, false );
}
else if( win.attachEvent ){
// IE事件模型(6、7、8)
win.attachEvent( "onresize", callMedia );
}
2.提取CSS文件路径
var doc = win.document,
docElem = doc.documentElement,
mediastyles = [],
rules = [],
appendedEls = [],
parsedSheets = {},
resizeThrottle = 30,
head = doc.getElementsByTagName( "head" )[0] || docElem,
base = doc.getElementsByTagName( "base" )[0],
links = head.getElementsByTagName( "link" ),
requestQueue = [], // 遍历CSS路径
ripCSS = function(){
for( var i = 0; i < links.length; i++ ){
var sheet = links[ i ],
href = sheet.href,
media = sheet.media,
isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet"; if( !!href && isCSS && !parsedSheets[ href ] ){
// selectivizr exposes css through the rawCssText expando
if (sheet.styleSheet && sheet.styleSheet.rawCssText) {
translate( sheet.styleSheet.rawCssText, href, media );
parsedSheets[ href ] = true;
} else {
// 判断条件:
// 1.有形如http://这样的href需要判断http://后面的根目录是否等于location.host。
// 2.不以形如http://这样开头的href,同时不包含<base>,
// 所以它不支持带有<base>的相对href
if( (!/^([a-zA-Z:]*\/\/)/.test( href ) && !base) ||
href.replace( RegExp.$1, "" ).split( "/" )[0] === win.location.host ){
requestQueue.push( {
href: href,
media: media
} );
}
}
}
}
makeRequests();
}
3.发送ajax请求返回CSS内容
// 递归执行获得CSS文本
// 递归配合shift()可以保证最后被遍历的CSS具有最高的优先级
makeRequests = function(){
if( requestQueue.length ){
var thisRequest = requestQueue.shift(); ajax( thisRequest.href, function( styles ){
translate( styles, thisRequest.href, thisRequest.media );
parsedSheets[ thisRequest.href ] = true; // 在递归函数外面包裹一层setTimeout,
// 使得函数以异步的方式执行,防止栈溢出
win.setTimeout(function(){ makeRequests(); },0);
} );
}
}
// ajax方法
ajax = function( url, callback ) {
var req = xmlHttp();
if (!req){
return;
}
req.open( "GET", url, true );
req.onreadystatechange = function () {
if ( req.readyState !== 4 || req.status !== 200 && req.status !== 304 ){
return;
}
callback( req.responseText );
};
if ( req.readyState === 4 ){
return;
}
req.send( null );
}
4.取出CSS中具有形如 @media screen and (max-width: 480px) 的各个块
translate = function( styles, href, media ){
// 匹配各个@media {...}
var qs = styles.match( /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi ),
ql = qs && qs.length || 0; //try to get CSS path
href = href.substring( 0, href.lastIndexOf( "/" ) ); var repUrls = function( css ){
return css.replace( /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g, "$1" + href + "$2$3" );
},
// useMedia=true表示<link>是否具有media属性并且
// CSS样式中没有@media块
useMedia = !ql && media; //if path exists, tack on trailing slash
if( href.length ){ href += "/"; } if( useMedia ){
ql = 1;
} for( var i = 0; i < ql; i++ ){
var fullq, thisq, eachq, eql; //media attr
if( useMedia ){
fullq = media;
rules.push( repUrls( styles ) );
}
// rules保存了每个@media块内部的样式
else{
fullq = qs[ i ].match( /@media *([^\{]+)\{([\S\s]+?)$/ ) && RegExp.$1;
rules.push( RegExp.$2 && repUrls( RegExp.$2 ) );
} eachq = fullq.split( "," );
eql = eachq.length; for( var j = 0; j < eql; j++ ){
thisq = eachq[ j ];
// 所有media块
mediastyles.push( {
media : thisq.split( "(" )[ 0 ].match( /(only\s+)?([a-zA-Z]+)\s?/ ) && RegExp.$2 || "all",
// 对应media块在rules数组中的样式
rules : rules.length - 1,
hasquery : thisq.indexOf("(") > -1,
minw : thisq.match( /\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ),
maxw : thisq.match( /\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" )
} );
}
} applyMedia();
}
5.将匹配的样式加入文档中
applyMedia = function( fromResize ){
var name = "clientWidth",
docElemProp = docElem[ name ],
// 取得当前页面宽度
currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[ name ] || docElemProp,
styleBlocks = {},
lastLink = links[ links.length-1 ],
now = (new Date()).getTime(); // 函数节流,延迟调用
if( fromResize && lastCall && now - lastCall < resizeThrottle ){
win.clearTimeout( resizeDefer );
resizeDefer = win.setTimeout( applyMedia, resizeThrottle );
return;
}
else {
lastCall = now;
}
// 遍历所有media
for( var i in mediastyles ){
if( mediastyles.hasOwnProperty( i ) ){
var thisstyle = mediastyles[ i ],
min = thisstyle.minw,
max = thisstyle.maxw,
minnull = min === null,
maxnull = max === null,
em = "em"; // 支持以em为单位的宽度,定义了一个getEmValue方法计算em能换算成多少px if( !!min ){
min = parseFloat( min ) * ( min.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
}
if( !!max ){
max = parseFloat( max ) * ( max.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
} // 筛选宽度匹配的样式
if( !thisstyle.hasquery || ( !minnull || !maxnull ) && ( minnull || currWidth >= min ) && ( maxnull || currWidth <= max ) ){
if( !styleBlocks[ thisstyle.media ] ){
styleBlocks[ thisstyle.media ] = [];
}
styleBlocks[ thisstyle.media ].push( rules[ thisstyle.rules ] );
}
}
} // 删除已存在的respond样式
for( var j in appendedEls ){
if( appendedEls.hasOwnProperty( j ) ){
if( appendedEls[ j ] && appendedEls[ j ].parentNode === head ){
head.removeChild( appendedEls[ j ] );
}
}
} // 在文档中插入respond样式
for( var k in styleBlocks ){
if( styleBlocks.hasOwnProperty( k ) ){
var ss = doc.createElement( "style" ),
css = styleBlocks[ k ].join( "\n" ); ss.type = "text/css";
ss.media = k; // originally, ss was appended to a documentFragment and sheets were appended in bulk.
// this caused crashes in IE in a number of circumstances, such as when the HTML element had a bg image set,
// so appending beforehand seems best. Thanks to @dvelyk for the initial research on this one!
head.insertBefore( ss, lastLink.nextSibling ); if ( ss.styleSheet ){
// IE下
ss.styleSheet.cssText = css;
}
else {
ss.appendChild( doc.createTextNode( css ) );
} //存储在appendedEls中,下次以便跟踪删除
appendedEls.push( ss );
}
}
}
三、Respond.js带来的跨域请求问题
Respond.js通过ajax请求CSS文件,所以如果CSS文件存放在CDN上面(或者子域中),那么需要引入一个代理页面实现跨域连接。
引入方法:
<!-- 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>
Media Queries之Respond.js的更多相关文章
- Respond.js – 让不懂爱的 IE6-8 支持 CSS3 Media Query
respond.min.js <script src="js/respond.min.js"></script> respond.min.js代码: /*! ...
- IE9中Media queries在iframe无效的解决方法
在css中有5个media querie @media screen and(min-width:0px)and(max-width:319px){ body {background-color:re ...
- Respond.js – 让 IE6-8 支持 CSS3 Media Query
Respond.js 是一个快速.轻量的 polyfill,用于为 IE6-8 以及其它不支持 CSS3 Media Queries 的浏览器提供媒体查询的 min-width 和 max-width ...
- Respond.js让IE6-8支持CSS3 Media Query
原文地址:http://caibaojian.com/respondjs.html 使用方式 官方demo地址:http://scottjehl.github.com/Respond/test ...
- css3 @media支持ie8用respond.js 解决IE6~8的响应式布局问题
respond.js插件实现原理 接下来,需要理解respond.js的实现思路: 第一步,将head中所有外部引入的CSS文件路径取出来存储到一个数组当中: 第二步,遍历数组,并一个个发送AJAX请 ...
- css3的媒体查询(Media Queries)
我今天就总结一下响应式设计的核心CSS技术Media(媒体查询器)的用法. 先看一个简单的例子: <link rel="stylesheet" media="scr ...
- CSS3的媒体查询(Media Queries)与移动设备显示尺寸大全
媒体查询介绍 我今天就总结一下响应式设计的核心CSS技术Media(媒体查询器)的用法. 先看一个简单的例子: <link rel="stylesheet" media=&q ...
- 第11章 Media Queries 与Responsive 设计
Media Queries--媒体类型(一) 随着科学技术不断的向前发展,网页的浏览终端越来越多样化,用户可以通过:宽屏电视.台式电脑.笔记本电脑.平板电脑和智能手机来访问你的网站.尽管你无法保证一个 ...
- Respond.js的作用
在html页面中我们经常看到 <!--[if lt IE 9]> //判断当前浏览器的版本是否小于IE 9 <script src="https:/ ...
随机推荐
- Postgres中tuple的组装与插入
1.相关的数据类型 我们先看相关的数据类型: HeapTupleData(src/include/access/htup.h) typedef struct HeapTupleData { uint3 ...
- nfs挂载无法卸载
故障现象:今天发现服务器的upload负载很高,到18左右,同时df查看磁盘命令卡住 用top\vmstat\iostat查看并未发现可以服务或进程. 上网查发现可能是nfs问题. 卸载nfs挂载的方 ...
- 64.Minimum Path Sum---dp
题目链接:https://leetcode.com/problems/minimum-path-sum/description/ 题目大意:从左上到右下的路径中,找出路径和最小的路径(与62,63题相 ...
- csu 1769(数学)
1769: 想打架吗?算我一个!所有人,都过来!(3) Time Limit: 2 Sec Memory Limit: 128 MBSubmit: 262 Solved: 76[Submit][S ...
- mac环境下使用brew安装kafka
1.安装kafka brew install kafka note: ·kafka使用zookeeper管理,安装过程会自动安装zookeeper ·安装目录:/usr/local/Cellar/ka ...
- Download Percona Monitoring Plugins
https://www.percona.com/downloads/percona-monitoring-plugins/LATEST/
- GUC-3 模拟CAS算法
/* * 模拟 CAS 算法 */ public class TestCompareAndSwap { public static void main(String[] args) { final C ...
- 通过NVM安装node
NVM(Node version manager)顾名思义,就是Node.js的版本管理软件,可以轻松的在Node.js各个版本间切换,项目源码GitHub 1.下载并安装NVM脚本 curl htt ...
- BASH 的调试技巧
平时在写 BASH 脚本时,总是会碰到让人抓狂的 BUG.和 C/C++ 这么丰富的调试工具相比,BASH 又有什么调试手段呢? 1 echo/print (普通技) 打印一些变量,或者提示信息.这应 ...
- 2017-2018-1 20179202《Linux内核原理与分析》第四周作业
一.跟踪分析内核的启动过程实验 : 1.启动Menuos: qemu仿真kernel: qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd ...