Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Media queries for inline styles #154

Open
wants to merge 2 commits into from

2 participants

Kondrat Shmoylov Scott Jehl
Kondrat Shmoylov

Here are some changes for support media queries from inlined style tags

Scott Jehl scottjehl commented on the diff
respond.src.js
((27 lines not shown))
}
}
+
+ for(i = 0, l = $styles.length; i < l; i++ ){
+
+ elm = $styles[i];
+ inlineStyleContent = elm.innerHTML || elm.innerText || elm.textContent;
Scott Jehl Owner

Interesting changes, here, thanks! Have you tested this in IE6-8? I'm curious how you've worked around the issue of all un-supported media types/queries being converted into @media UNKNOWN when fetching the text in IE.

Kondrat Shmoylov
ikondrat added a note
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Eric Berens ericberens referenced this pull request
Open

IE8 Included CSS #278

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 12, 2012
Commits on Oct 2, 2012
  1. Support media queries from inline styles

    Kondrat Shmoylov authored
This page is out of date. Refresh to see the latest.
3  respond.min.js
View
@@ -1,6 +1,5 @@
/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
/*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
window.matchMedia=window.matchMedia||(function(e,f){var c,a=e.documentElement,b=a.firstElementChild||a.firstChild,d=e.createElement("body"),g=e.createElement("div");g.id="mq-test-1";g.style.cssText="position:absolute;top:-100em";d.style.background="none";d.appendChild(g);return function(h){g.innerHTML='&shy;<style media="'+h+'"> #mq-test-1 { width: 42px; }</style>';a.insertBefore(d,b);c=g.offsetWidth==42;a.removeChild(d);return{matches:c,media:h}}})(document);
-
/*! Respond.js v1.1.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */
-(function(e){e.respond={};respond.update=function(){};respond.mediaQueriesSupported=e.matchMedia&&e.matchMedia("only all").matches;if(respond.mediaQueriesSupported){return}var w=e.document,s=w.documentElement,i=[],k=[],q=[],o={},h=30,f=w.getElementsByTagName("head")[0]||s,g=w.getElementsByTagName("base")[0],b=f.getElementsByTagName("link"),d=[],a=function(){var D=b,y=D.length,B=0,A,z,C,x;for(;B<y;B++){A=D[B],z=A.href,C=A.media,x=A.rel&&A.rel.toLowerCase()==="stylesheet";if(!!z&&x&&!o[z]){if(A.styleSheet&&A.styleSheet.rawCssText){m(A.styleSheet.rawCssText,z,C);o[z]=true}else{if((!/^([a-zA-Z:]*\/\/)/.test(z)&&!g)||z.replace(RegExp.$1,"").split("/")[0]===e.location.host){d.push({href:z,media:C})}}}}u()},u=function(){if(d.length){var x=d.shift();n(x.href,function(y){m(y,x.href,x.media);o[x.href]=true;u()})}},m=function(I,x,z){var G=I.match(/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi),J=G&&G.length||0,x=x.substring(0,x.lastIndexOf("/")),y=function(K){return K.replace(/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,"$1"+x+"$2$3")},A=!J&&z,D=0,C,E,F,B,H;if(x.length){x+="/"}if(A){J=1}for(;D<J;D++){C=0;if(A){E=z;k.push(y(I))}else{E=G[D].match(/@media *([^\{]+)\{([\S\s]+?)$/)&&RegExp.$1;k.push(RegExp.$2&&y(RegExp.$2))}B=E.split(",");H=B.length;for(;C<H;C++){F=B[C];i.push({media:F.split("(")[0].match(/(only\s+)?([a-zA-Z]+)\s?/)&&RegExp.$2||"all",rules:k.length-1,hasquery:F.indexOf("(")>-1,minw:F.match(/\(min\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:F.match(/\(max\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}}j()},l,r,v=function(){var z,A=w.createElement("div"),x=w.body,y=false;A.style.cssText="position:absolute;font-size:1em;width:1em";if(!x){x=y=w.createElement("body");x.style.background="none"}x.appendChild(A);s.insertBefore(x,s.firstChild);z=A.offsetWidth;if(y){s.removeChild(x)}else{x.removeChild(A)}z=p=parseFloat(z);return z},p,j=function(I){var x="clientWidth",B=s[x],H=w.compatMode==="CSS1Compat"&&B||w.body[x]||B,D={},G=b[b.length-1],z=(new Date()).getTime();if(I&&l&&z-l<h){clearTimeout(r);r=setTimeout(j,h);return}else{l=z}for(var E in i){var K=i[E],C=K.minw,J=K.maxw,A=C===null,L=J===null,y="em";if(!!C){C=parseFloat(C)*(C.indexOf(y)>-1?(p||v()):1)}if(!!J){J=parseFloat(J)*(J.indexOf(y)>-1?(p||v()):1)}if(!K.hasquery||(!A||!L)&&(A||H>=C)&&(L||H<=J)){if(!D[K.media]){D[K.media]=[]}D[K.media].push(k[K.rules])}}for(var E in q){if(q[E]&&q[E].parentNode===f){f.removeChild(q[E])}}for(var E in D){var M=w.createElement("style"),F=D[E].join("\n");M.type="text/css";M.media=E;f.insertBefore(M,G.nextSibling);if(M.styleSheet){M.styleSheet.cssText=F}else{M.appendChild(w.createTextNode(F))}q.push(M)}},n=function(x,z){var y=c();if(!y){return}y.open("GET",x,true);y.onreadystatechange=function(){if(y.readyState!=4||y.status!=200&&y.status!=304){return}z(y.responseText)};if(y.readyState==4){return}y.send(null)},c=(function(){var x=false;try{x=new XMLHttpRequest()}catch(y){x=new ActiveXObject("Microsoft.XMLHTTP")}return function(){return x}})();a();respond.update=a;function t(){j(true)}if(e.addEventListener){e.addEventListener("resize",t,false)}else{if(e.attachEvent){e.attachEvent("onresize",t)}}})(this);
+(function(g){g.respond={};respond.update=function(){};respond.mediaQueriesSupported=g.matchMedia&&g.matchMedia("only all").matches;if(respond.mediaQueriesSupported){return}var A=g.document,w=A.documentElement,l=[],n=[],u=[],s={},k=30,h=A.getElementsByTagName("head")[0]||w,i=A.getElementsByTagName("base")[0],b=h.getElementsByTagName("link"),r=$('style[type="text/css"]'),f=[],c=null,e=function(D,C){var B=new RegExp("\\("+C+":[\\s]*([\\s]*[0-9\\.]+)(px|em)[\\s]*\\)");return(D.match(B)&&parseFloat(RegExp.$1)+(RegExp.$2||""))},a=function(){var G=b,E=G.length,F=0,D,I,H,J,B,C,K;for(;F<E;F++){J=G[F],B=J.href,C=J.media,K=J.rel&&J.rel.toLowerCase()==="stylesheet";if(!!B&&K&&!s[B]){if(J.styleSheet&&J.styleSheet.rawCssText){p(J.styleSheet.rawCssText,B,C);s[B]=true}else{if((!/^([a-zA-Z:]*\/\/)/.test(B)&&!i)||B.replace(RegExp.$1,"").split("/")[0]===g.location.host){f.push({href:B,media:C})}}}}for(F=0,D=r.length;F<D;F++){I=r[F];H=I.innerHTML||I.innerText||I.textContent;if(H){p(H)}}y()},y=function(){if(f.length){var B=f.shift();q(B.href,function(C){p(C,B.href,B.media);s[B.href]=true;y()})}},p=function(M,B,D){B=B||"";D=D||"";var K=M.match(/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi),N=K&&K.length||0,B=B.substring(0,B.lastIndexOf("/")),C=function(O){return O.replace(/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,"$1"+B+"$2$3")},E=!N&&D,H=0,G,I,J,F,L;if(B.length){B+="/"}if(E){N=1}for(;H<N;H++){G=0;if(E){I=D;n.push(C(M))}else{I=K[H].match(/@media *([^\{]+)\{([\S\s]+?)$/)&&RegExp.$1;n.push(RegExp.$2&&C(RegExp.$2))}F=I.split(",");L=F.length;for(;G<L;G++){J=F[G];l.push({media:J.split("(")[0].match(/(only\s+)?([a-zA-Z]+)\s?/)&&RegExp.$2||"all",rules:n.length-1,hasquery:J.indexOf("(")>-1,minw:e(J,"min-width"),maxw:e(J,"max-width"),minh:e(J,"min-height"),maxh:e(J,"max-height")})}}c&&window.clearTimeout(c);c=window.setTimeout(function(){m()},50)},o,v,z=function(){var D,E=A.createElement("div"),B=A.body,C=false;E.style.cssText="position:absolute;font-size:1em;width:1em";if(!B){B=C=A.createElement("body");B.style.background="none"}B.appendChild(E);w.insertBefore(B,w.firstChild);D=E.offsetWidth;if(C){w.removeChild(B)}else{B.removeChild(E)}D=t=parseFloat(D);return D},j=function(B){return parseFloat(B)*(B.indexOf("em")>-1?(t||z()):1)},t,m=function(S){var D="offsetWidth",K="offsetHeight",X=w[D],G=w[K],B=A.compatMode==="CSS1Compat"&&X||A.body[D]||X,H=A.compatMode==="CSS1Compat"&&G||A.body[K]||G,V={},W=b[b.length-1],C=(new Date()).getTime(),R=0,Q=0;if(S&&o&&C-o<k){clearTimeout(v);v=setTimeout(m,k);return}else{o=C}for(R=0,Q=l.length;R<Q;R++){var T=l[R],F=T.minw,E=T.maxw,M=T.minh,L=T.maxh,N=F===null,U=E===null,I=M===null,O=L===null;if(!N){F=j(F)}if(!U){E=j(E)}if(!I){M=j(M)}if(!O){L=j(L)}if(!T.hasquery||(!N||!U)&&(N||B>=F)&&(U||B<=E)||(!I||!O)&&(I||H>=M)&&(O||H<=L)){if(!V[T.media]){V[T.media]=[]}V[T.media].push(n[T.rules])}}for(R=0,Q=u.length;R<Q;R++){if(u[R]&&u[R].parentNode===h){h.removeChild(u[R])}}for(var R in V){if(V.hasOwnProperty(R)){var P=A.createElement("style"),J=V[R].join("\n");P.type="text/css";P.media=R;h.insertBefore(P,W.nextSibling);if(P.styleSheet){P.styleSheet.cssText=J}else{P.appendChild(A.createTextNode(J))}u.push(P)}}},q=function(B,D){var C=d();if(!C){return}C.open("GET",B,true);C.onreadystatechange=function(){if(C.readyState!=4||C.status!=200&&C.status!=304){return}D(C.responseText)};if(C.readyState==4){return}C.send(null)},d=(function(){var B=false;try{B=new XMLHttpRequest()}catch(C){B=new ActiveXObject("Microsoft.XMLHTTP")}return function(){return B}})();a();respond.update=a;function x(){m(true)}if(g.addEventListener){g.addEventListener("resize",x,false)}else{if(g.attachEvent){g.attachEvent("onresize",x)}}})(this);
158 respond.src.js
View
@@ -29,7 +29,6 @@ window.matchMedia = window.matchMedia || (function(doc, undefined){
-
/*! Respond.js v1.1.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */
(function( win ){
//exposed namespace
@@ -55,13 +54,19 @@ window.matchMedia = window.matchMedia || (function(doc, undefined){
head = doc.getElementsByTagName( "head" )[0] || docElem,
base = doc.getElementsByTagName( "base" )[0],
links = head.getElementsByTagName( "link" ),
+ $styles = $('style[type="text/css"]'),
requestQueue = [],
+ tm = null,
+ getDecimalValueByName = function( propValue, propName ){
+ var re = new RegExp("\\(" + propName + ":[\\s]*([\\s]*[0-9\\.]+)(px|em)[\\s]*\\)");
+ return (propValue.match( re ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ));
+ },
//loop stylesheets, send text content to translate
ripCSS = function(){
var sheets = links,
sl = sheets.length,
- i = 0,
+ i = 0,l,elm,inlineStyleContent,
//vars for loop:
sheet, href, media, isCSS;
@@ -73,21 +78,43 @@ window.matchMedia = window.matchMedia || (function(doc, undefined){
//only links plz and prevent re-parsing
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 {
- if( (!/^([a-zA-Z:]*\/\/)/.test( href ) && !base)
- || href.replace( RegExp.$1, "" ).split( "/" )[0] === win.location.host ){
+
+ if( (!/^([a-zA-Z:]*\/\/)/.test( href ) && !base) ||
+ href.replace( RegExp.$1, "" ).split( "/" )[0] === win.location.host ){
+
requestQueue.push( {
href: href,
media: media
} );
+
}
+
}
+
}
}
+
+ for(i = 0, l = $styles.length; i < l; i++ ){
+
+ elm = $styles[i];
+ inlineStyleContent = elm.innerHTML || elm.innerText || elm.textContent;
Scott Jehl Owner

Interesting changes, here, thanks! Have you tested this in IE6-8? I'm curious how you've worked around the issue of all un-supported media types/queries being converted into @media UNKNOWN when fetching the text in IE.

Kondrat Shmoylov
ikondrat added a note
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+
+ if (inlineStyleContent) {
+
+ translate( inlineStyleContent );
+
+ }
+
+ }
+
makeRequests();
},
@@ -106,6 +133,9 @@ window.matchMedia = window.matchMedia || (function(doc, undefined){
//find media blocks in css text, convert to style blocks
translate = function( styles, href, media ){
+ href = href || "";
+ media = media || "";
+
var qs = styles.match( /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi ),
ql = qs && qs.length || 0,
//try to get CSS path
@@ -153,15 +183,21 @@ window.matchMedia = window.matchMedia || (function(doc, undefined){
media : thisq.split( "(" )[ 0 ].match( /(only\s+)?([a-zA-Z]+)\s?/ ) && RegExp.$2 || "all",
rules : rules.length - 1,
hasquery: thisq.indexOf("(") > -1,
- minw : thisq.match( /\(min\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ),
- maxw : thisq.match( /\(max\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" )
+ minw : getDecimalValueByName( thisq, 'min\-width' ),
+ maxw : getDecimalValueByName( thisq, 'max\-width' ),
+ minh : getDecimalValueByName( thisq, 'min\-height' ),
+ maxh : getDecimalValueByName( thisq, 'max\-height' )
} );
}
}
- applyMedia();
+ // It's fix for calling applyMedia once for all styles links
+ tm && window.clearTimeout( tm );
+ tm = window.setTimeout(function(){
+ applyMedia()
+ }, 50);
},
-
+
lastCall,
resizeDefer,
@@ -198,18 +234,27 @@ window.matchMedia = window.matchMedia || (function(doc, undefined){
return ret;
},
+
+ getCSSRuleValue = function( rule ){
+ return parseFloat( rule ) * ( rule.indexOf( "em" ) > -1 ? ( eminpx || getEmValue() ) : 1 );
+ },
//cached container for 1em value, populated the first time it's needed
eminpx,
//enable/disable styles
- 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();
+ applyMedia = function( fromResize ){
+ var nameW = "offsetWidth",
+ nameH = "offsetHeight",
+ docElemPropW = docElem[ nameW ],
+ docElemPropH = docElem[ nameH ],
+ currWidth = doc.compatMode === "CSS1Compat" && docElemPropW || doc.body[ nameW ] || docElemPropW,
+ currHeight = doc.compatMode === "CSS1Compat" && docElemPropH || doc.body[ nameH ] || docElemPropH,
+ styleBlocks = {},
+ lastLink = links[ links.length-1 ],
+ now = (new Date()).getTime(),
+ i = 0,
+ l = 0;
//throttle resize calls
if( fromResize && lastCall && now - lastCall < resizeThrottle ){
@@ -220,24 +265,37 @@ window.matchMedia = window.matchMedia || (function(doc, undefined){
else {
lastCall = now;
}
-
- for( var i in mediastyles ){
+
+ for( i = 0, l = mediastyles.length; i < l; i++ ){
+
var thisstyle = mediastyles[ i ],
- min = thisstyle.minw,
- max = thisstyle.maxw,
- minnull = min === null,
- maxnull = max === null,
- em = "em";
-
- if( !!min ){
- min = parseFloat( min ) * ( min.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
+ minw = thisstyle.minw,
+ maxw = thisstyle.maxw,
+ minh = thisstyle.minh,
+ maxh = thisstyle.maxh,
+ minwnull = minw === null,
+ maxwnull = maxw === null,
+ minhnull = minh === null,
+ maxhnull = maxh === null;
+
+ if( !minwnull ){
+ minw = getCSSRuleValue( minw );
}
- if( !!max ){
- max = parseFloat( max ) * ( max.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
+ if( !maxwnull ){
+ maxw = getCSSRuleValue( maxw );
}
-
+ if( !minhnull ){
+ minh = getCSSRuleValue( minh );
+ }
+ if( !maxhnull ){
+ maxh = getCSSRuleValue( maxh );
+ }
+
// if there's no media query at all (the () part), or min or max is not null, and if either is present, they're true
- if( !thisstyle.hasquery || ( !minnull || !maxnull ) && ( minnull || currWidth >= min ) && ( maxnull || currWidth <= max ) ){
+ if( !thisstyle.hasquery ||
+ ( !minwnull || !maxwnull ) && ( minwnull || currWidth >= minw ) && ( maxwnull || currWidth <= maxw ) ||
+ ( !minhnull || !maxhnull ) && ( minhnull || currHeight >= minh ) && ( maxhnull || currHeight <= maxh )
+ ){
if( !styleBlocks[ thisstyle.media ] ){
styleBlocks[ thisstyle.media ] = [];
}
@@ -246,7 +304,7 @@ window.matchMedia = window.matchMedia || (function(doc, undefined){
}
//remove any existing respond style element(s)
- for( var i in appendedEls ){
+ for( i = 0, l = appendedEls.length; i < l; i++ ){
if( appendedEls[ i ] && appendedEls[ i ].parentNode === head ){
head.removeChild( appendedEls[ i ] );
}
@@ -254,25 +312,27 @@ window.matchMedia = window.matchMedia || (function(doc, undefined){
//inject active styles, grouped by media type
for( var i in styleBlocks ){
- var ss = doc.createElement( "style" ),
- css = styleBlocks[ i ].join( "\n" );
-
- ss.type = "text/css";
- ss.media = i;
-
- //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 ){
- ss.styleSheet.cssText = css;
- }
- else {
- ss.appendChild( doc.createTextNode( css ) );
- }
-
- //push to appendedEls to track for later removal
- appendedEls.push( ss );
+ if( styleBlocks.hasOwnProperty( i ) ){
+ var ss = doc.createElement( "style" ),
+ css = styleBlocks[ i ].join( "\n" );
+
+ ss.type = "text/css";
+ ss.media = i;
+
+ //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 ){
+ ss.styleSheet.cssText = css;
+ }
+ else {
+ ss.appendChild( doc.createTextNode( css ) );
+ }
+
+ //push to appendedEls to track for later removal
+ appendedEls.push( ss );
+ }
}
},
//tweaked Ajax functions from Quirksmode
100 test/README.md
View
@@ -0,0 +1,100 @@
+# Respond.js
+### A fast & lightweight polyfill for min/max-width CSS3 Media Queries (for IE 6-8, and more)
+
+ - Copyright 2011: Scott Jehl, scottjehl.com
+ - Dual licensed under the MIT or GPL Version 2 licenses.
+
+The goal of this script is to provide a fast and lightweight (3kb minified / 1kb gzipped) script to enable [responsive web designs](http://www.alistapart.com/articles/responsive-web-design/) in browsers that don't support CSS3 Media Queries - in particular, Internet Explorer 8 and under. It's written in such a way that it will probably patch support for other non-supporting browsers as well (more information on that soon).
+
+If you're unfamiliar with the concepts surrounding Responsive Web Design, you can read up [here](http://www.alistapart.com/articles/responsive-web-design/) and also [here](http://filamentgroup.com/examples/responsive-images/)
+
+[Demo page](http://scottjehl.github.com/Respond/test/test.html) (the colors change to show media queries working)
+
+
+Usage Instructions
+======
+
+1. Craft your CSS with min/max-width media queries to adapt your layout from mobile (first) all the way up to desktop
+
+
+<pre>
+ @media screen and (min-width: 480px){
+ ...styles for 480px and up go here
+ }
+</pre>
+
+2. Reference the respond.min.js script (1kb min/gzipped) after all of your CSS (the earlier it runs, the greater chance IE users will not see a flash of um-media'd content)
+
+3. Crack open Internet Explorer and pump fists in delight
+
+
+CDN/X-Domain Setup
+======
+
+Respond.js works by requesting a pristine copy of your CSS via AJAX, so if you host your stylesheets on a CDN (or a subdomain), you'll need to upload a proxy page to enable cross-domain communication.
+
+See `cross-domain/example.html` for a demo:
+
+- Upload `cross-domain/respond-proxy.html` to your external domain
+- Upload `cross-domain/respond.proxy.gif` to your origin domain
+- Reference the file(s) via `<link />` element(s):
+
+<pre>
+ &lt;!-- Respond.js proxy on external server --&gt;
+ &lt;link href=&quot;http://externalcdn.com/respond-proxy.html&quot; id=&quot;respond-proxy&quot; rel=&quot;respond-proxy&quot; /&gt;
+
+ &lt;!-- Respond.js redirect location on local server --&gt;
+ &lt;link href=&quot;/path/to/respond.proxy.gif&quot; id=&quot;respond-redirect&quot; rel=&quot;respond-redirect&quot; /&gt;
+
+ &lt;!-- Respond.js proxy script on local server --&gt;
+ &lt;script src="/path/to/respond.proxy.js"&gt;&lt;/script&gt;
+</pre>
+
+Note: HUGE thanks to @doctyper for the contributions in the cross-domain proxy!
+
+
+Support & Caveats
+======
+
+Some notes to keep in mind:
+
+- This script's focus is purposely very narrow: only min-width and max-width media queries and all media types (screen, print, etc) are translated to non-supporting browsers. I wanted to keep things simple for filesize, maintenance, and performance, so I've intentionally limited support to queries that are essential to building a (mobile-first) responsive design. In the future, I may rework things a bit to include a hook for patching-in additional media query features - stay tuned!
+
+- Browsers that natively support CSS3 Media Queries are opted-out of running this script as quickly as possible. In testing for support, all other browsers are subjected to a quick test to determine whether they support media queries or not before proceeding to run the script. This test is now included separately at the top, and uses the window.matchMedia polyfill found here: https://github.com/paulirish/matchMedia.js . If you are already including this polyfill via Modernizr or otherwise, feel free to remove that part.
+
+- This script relies on no other scripts or frameworks (aside from the included matchMedia polyfill), and is optimized for mobile delivery (~1kb total filesize min/gzip)
+
+- As you might guess, this implementation is quite dumb in regards to CSS parsing rules. This is a good thing, because that allows it to run really fast, but it's looseness may also cause unexpected behavior. For example: if you enclose a whole media query in a comment intending to disable its rules, you'll probably find that those rules will end up enabled in non-media-query-supporting browsers.
+
+- Respond.js doesn't parse CSS refrenced via @import, nor does it work with media queries within style elements, as those styles can't be re-requested for parsing.
+
+- Due to security restrictions, some browsers may not allow this script to work on file:// urls (because it uses xmlHttpRequest). Run it on a web server.
+
+- Currently, media attributes on link elements are supported, but only if the linked stylesheet contains no media queries. If it does contain queries, the media attribute will be ignored and the internal queries will be parsed normally. In other words, @media statements in the CSS take priority.
+
+- Reportedly, if CSS files are encoded in UTF-8 with Byte-Order-Mark (BOM), they will not work with Respond.js in IE7 or IE8. Noted in issue #97
+
+- WARNING: Including @font-face rules inside a media query will cause IE7 and IE8 to hang during load. To work around this, place @font-face rules in the wide open, as a sibling to other media queries.
+
+
+How's it work?
+======
+Basically, the script loops through the CSS referenced in the page and runs a regular expression or two on their contents to find media queries and their associated blocks of CSS. In Internet Explorer, the content of the stylesheet is impossible to retrieve in its pre-parsed state (which in IE 8-, means its media queries are removed from the text), so Respond.js re-requests the CSS files using Ajax and parses the text response from there. Be sure to configure your CSS files' caching properly so that this re-request doesn't actually go to the server, hitting your browser cache instead.
+
+From there, each media query block is appended to the head in order via style elements, and those style elements are enabled and disabled (read: appended and removed from the DOM) depending on how their min/max width compares with the browser width. The media attribute on the style elements will match that of the query in the CSS, so it could be "screen", "projector", or whatever you want. Any relative paths contained in the CSS will be prefixed by their stylesheet's href, so image paths will direct to their proper destination
+
+API Options?
+======
+Sure, a couple:
+
+- respond.update() : rerun the parser (helpful if you added a stylesheet to the page and it needs to be translated)
+- respond.mediaQueriesSupported: set to true if the browser natively supports media queries.
+
+
+
+
+Alternatives to this script
+======
+This isn't the only CSS3 Media Query polyfill script out there; but it damn well may be the fastest.
+
+If you're looking for more robust CSS3 Media Query support, you might check out http://code.google.com/p/css3-mediaqueries-js/. In testing, I've found that script to be noticeably slow when rendering complex responsive designs (both in filesize and performance), but it really does support a lot more media query features than this script. Big hat tip to the authors! :)
24 test/cross-domain/example.html
View
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8" />
+ <title>Respond JS Test Page</title>
+ <link href="http://scottjehl.com/respond-proxy/test.css" rel="stylesheet"/>
+ <link href="http://scottjehl.com/respond-proxy/test2.css" media="screen and (min-width: 600px)" rel="stylesheet"/>
+ <script src="../respond.src.js"></script>
+
+ <!-- Respond.js proxy on external server -->
+ <link href="http://scottjehl.com/respond-proxy/respond-proxy.html" id="respond-proxy" rel="respond-proxy" />
+ <link href="respond.proxy.gif" id="respond-redirect" rel="respond-redirect" />
+ <script src="respond.proxy.js"></script>
+</head>
+<body>
+ <p>This is a visual test file for cross-domain proxy.</p>
+
+ <p>The media queries in the included CSS file simply change the body's background color depending on the browser width. If you see any colors aside from black, then the media queries are working in your browser. You can resize your browser window to see it change on the fly.</p>
+
+
+ <p id="attribute-test">Media-attributes are working too! This should be visible above 600px.</p>
+
+</body>
+</html>
96 test/cross-domain/respond-proxy.html
View
@@ -0,0 +1,96 @@
+<!-- Respond.js: min/max-width media query polyfill. Remote proxy (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs -->
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8" />
+ <title>Respond JS Proxy</title>
+</head>
+<body>
+ <script>
+ (function () {
+ var domain, css, query, getQueryString, ajax, xmlHttp;
+
+ /*
+ http://stackoverflow.com/questions/4963673/get-url-array-variables-in-javascript-jquery/4963817#4963817
+ */
+ getQueryString = function() {
+ var ret = {}, parts, i, p;
+
+ parts = (document.location.toString().split("?")[1]).split("&");
+
+ for (i = 0; i < parts.length; i++) {
+
+ p = parts[i].split("=");
+ // so strings will be correctly parsed:
+ p[1] = decodeURIComponent(p[1].replace(/\+/g, " "));
+
+ if (p[0].search(/\[\]/) >= 0) { // then it"s an array
+ p[0] = p[0].replace("[]", "");
+
+ if (typeof ret[p[0]] != "object") {
+ ret[p[0]] = [];
+ }
+ ret[p[0]].push(p[1]);
+ } else {
+ ret[p[0]] = p[1];
+ }
+ }
+ return ret;
+ };
+
+ 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();
+ };
+
+ //define ajax obj
+ xmlHttp = (function() {
+ var xmlhttpmethod = false,
+ attempts = [
+ function(){ return new XMLHttpRequest(); },
+ function(){ return new ActiveXObject("Microsoft.XMLHTTP"); },
+ function(){ return new ActiveXObject("MSXML2.XMLHTTP.3.0"); }
+ ],
+ al = attempts.length;
+
+ while( al-- ){
+ try {
+ xmlhttpmethod = attempts[ al ]();
+ }
+ catch(e) {
+ continue;
+ }
+ break;
+ }
+ return function(){
+ return xmlhttpmethod;
+ };
+ })();
+
+ query = getQueryString();
+ css = query["css"];
+ domain = query["url"];
+
+ if (css && domain) {
+ ajax(css, function (response) {
+ window.name = response;
+ window.location.href = domain;
+ });
+ }
+ }());
+ </script>
+</body>
+</html>
BIN  test/cross-domain/respond.proxy.gif
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
127 test/cross-domain/respond.proxy.js
View
@@ -0,0 +1,127 @@
+/*! Respond.js: min/max-width media query polyfill. Remote proxy (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */
+(function(win, doc, undefined){
+ var docElem = doc.documentElement,
+ proxyURL = doc.getElementById("respond-proxy").href,
+ redirectURL = (doc.getElementById("respond-redirect") || location).href,
+ baseElem = doc.getElementsByTagName("base")[0],
+ urls = [],
+ refNode;
+
+ function encode(url){
+ return win.encodeURIComponent(url);
+ }
+
+ function fakejax( url, callback ){
+
+ var iframe,
+ AXO;
+
+ // All hail Google http://j.mp/iKMI19
+ // Behold, an iframe proxy without annoying clicky noises.
+ if ( "ActiveXObject" in win ) {
+ AXO = new ActiveXObject( "htmlfile" );
+ AXO.open();
+ AXO.write( '<iframe id="x"></iframe>' );
+ AXO.close();
+ iframe = AXO.getElementById( "x" );
+ } else {
+ iframe = doc.createElement( "iframe" );
+ iframe.style.cssText = "position:absolute;top:-99em";
+ docElem.insertBefore(iframe, docElem.firstElementChild || docElem.firstChild );
+ }
+
+ iframe.src = checkBaseURL(proxyURL) + "?url=" + encode(redirectURL) + "&css=" + encode(checkBaseURL(url));
+
+ function checkFrameName() {
+ var cssText;
+
+ try {
+ cssText = iframe.contentWindow.name;
+ }
+ catch (e) { }
+
+ if (cssText) {
+ // We've got what we need. Stop the iframe from loading further content.
+ iframe.src = "about:blank";
+ iframe.parentNode.removeChild(iframe);
+ iframe = null;
+
+
+ // Per http://j.mp/kn9EPh, not taking any chances. Flushing the ActiveXObject
+ if (AXO) {
+ AXO = null;
+
+ if (win.CollectGarbage) {
+ win.CollectGarbage();
+ }
+ }
+
+ callback(cssText);
+ }
+ else{
+ win.setTimeout(checkFrameName, 100);
+ }
+ }
+
+ win.setTimeout(checkFrameName, 500);
+ }
+
+ function checkBaseURL(href) {
+ if (baseElem && href.indexOf(baseElem.href) === -1) {
+ bref = (/\/$/).test(baseElem.href) ? baseElem.href : (baseElem.href + "/");
+ href = bref + href;
+ }
+
+ return href;
+ }
+
+ function checkRedirectURL() {
+ // IE6 & IE7 don't build out absolute urls in <link /> attributes.
+ // So respond.proxy.gif remains relative instead of http://example.com/respond.proxy.gif.
+ // This trickery resolves that issue.
+ if (~ !redirectURL.indexOf(location.host)) {
+
+ var fakeLink = doc.createElement("div");
+
+ fakeLink.innerHTML = '<a href="' + redirectURL + '"></a>';
+ docElem.insertBefore(fakeLink, docElem.firstElementChild || docElem.firstChild );
+
+ // Grab the parsed URL from that dummy object
+ redirectURL = fakeLink.firstChild.href;
+
+ // Clean up
+ fakeLink.parentNode.removeChild(fakeLink);
+ fakeLink = null;
+ }
+ }
+
+ function buildUrls(){
+ var links = doc.getElementsByTagName( "link" );
+
+ for( var i = 0, linkl = links.length; i < linkl; i++ ){
+
+ var thislink = links[i],
+ href = links[i].href,
+ extreg = (/^([a-zA-Z]+?:(\/\/)?(www\.)?)/).test( href ),
+ ext = (baseElem && !extreg) || extreg;
+
+ //make sure it's an external stylesheet
+ if( thislink.rel.indexOf( "stylesheet" ) >= 0 && ext ){
+ (function( link ){
+ fakejax( href, function( css ){
+ link.styleSheet.rawCssText = css;
+ respond.update();
+ } );
+ })( thislink );
+ }
+ }
+
+
+ }
+
+ if( !respond.mediaQueriesSupported ){
+ checkRedirectURL();
+ buildUrls();
+ }
+
+})( window, document );
5 test/respond.min.js
View
@@ -0,0 +1,5 @@
+/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
+/*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
+window.matchMedia=window.matchMedia||(function(e,f){var c,a=e.documentElement,b=a.firstElementChild||a.firstChild,d=e.createElement("body"),g=e.createElement("div");g.id="mq-test-1";g.style.cssText="position:absolute;top:-100em";d.style.background="none";d.appendChild(g);return function(h){g.innerHTML='&shy;<style media="'+h+'"> #mq-test-1 { width: 42px; }</style>';a.insertBefore(d,b);c=g.offsetWidth==42;a.removeChild(d);return{matches:c,media:h}}})(document);
+/*! Respond.js v1.1.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */
+(function(g){g.respond={};respond.update=function(){};respond.mediaQueriesSupported=g.matchMedia&&g.matchMedia("only all").matches;if(respond.mediaQueriesSupported){return}var z=g.document,v=z.documentElement,l=[],n=[],t=[],r={},k=30,h=z.getElementsByTagName("head")[0]||v,i=z.getElementsByTagName("base")[0],b=h.getElementsByTagName("link"),f=[],c=null,e=function(C,B){var A=new RegExp("\\("+B+":[\\s]*([\\s]*[0-9\\.]+)(px|em)[\\s]*\\)");return(C.match(A)&&parseFloat(RegExp.$1)+(RegExp.$2||""))},a=function(){var G=b,B=G.length,E=0,D,C,F,A;for(;E<B;E++){D=G[E],C=D.href,F=D.media,A=D.rel&&D.rel.toLowerCase()==="stylesheet";if(!!C&&A&&!r[C]){if(D.styleSheet&&D.styleSheet.rawCssText){p(D.styleSheet.rawCssText,C,F);r[C]=true}else{if((!/^([a-zA-Z:]*\/\/)/.test(C)&&!i)||C.replace(RegExp.$1,"").split("/")[0]===g.location.host){f.push({href:C,media:F})}}}}x()},x=function(){if(f.length){var A=f.shift();q(A.href,function(B){p(B,A.href,A.media);r[A.href]=true;x()})}},p=function(L,A,C){var J=L.match(/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi),M=J&&J.length||0,A=A.substring(0,A.lastIndexOf("/")),B=function(N){return N.replace(/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,"$1"+A+"$2$3")},D=!M&&C,G=0,F,H,I,E,K;if(A.length){A+="/"}if(D){M=1}for(;G<M;G++){F=0;if(D){H=C;n.push(B(L))}else{H=J[G].match(/@media *([^\{]+)\{([\S\s]+?)$/)&&RegExp.$1;n.push(RegExp.$2&&B(RegExp.$2))}E=H.split(",");K=E.length;for(;F<K;F++){I=E[F];l.push({media:I.split("(")[0].match(/(only\s+)?([a-zA-Z]+)\s?/)&&RegExp.$2||"all",rules:n.length-1,hasquery:I.indexOf("(")>-1,minw:e(I,"min-width"),maxw:e(I,"max-width"),minh:e(I,"min-height"),maxh:e(I,"max-height")})}}c&&window.clearTimeout(c);c=window.setTimeout(function(){m()},50)},o,u,y=function(){var C,D=z.createElement("div"),A=z.body,B=false;D.style.cssText="position:absolute;font-size:1em;width:1em";if(!A){A=B=z.createElement("body");A.style.background="none"}A.appendChild(D);v.insertBefore(A,v.firstChild);C=D.offsetWidth;if(B){v.removeChild(A)}else{A.removeChild(D)}C=s=parseFloat(C);return C},j=function(A){return parseFloat(A)*(A.indexOf("em")>-1?(s||y()):1)},s,m=function(R){var C="offsetWidth",J="offsetHeight",W=v[C],F=v[J],A=z.compatMode==="CSS1Compat"&&W||z.body[C]||W,G=z.compatMode==="CSS1Compat"&&F||z.body[J]||F,U={},V=b[b.length-1],B=(new Date()).getTime(),Q=0,P=0;if(R&&o&&B-o<k){clearTimeout(u);u=setTimeout(m,k);return}else{o=B}for(Q=0,P=l.length;Q<P;Q++){var S=l[Q],E=S.minw,D=S.maxw,L=S.minh,K=S.maxh,M=E===null,T=D===null,H=L===null,N=K===null;if(!M){E=j(E)}if(!T){D=j(D)}if(!H){L=j(L)}if(!N){K=j(K)}if(!S.hasquery||(!M||!T)&&(M||A>=E)&&(T||A<=D)||(!H||!N)&&(H||G>=L)&&(N||G<=K)){if(!U[S.media]){U[S.media]=[]}U[S.media].push(n[S.rules])}}for(Q=0,P=t.length;Q<P;Q++){if(t[Q]&&t[Q].parentNode===h){h.removeChild(t[Q])}}for(var Q in U){if(U.hasOwnProperty(Q)){var O=z.createElement("style"),I=U[Q].join("\n");O.type="text/css";O.media=Q;h.insertBefore(O,V.nextSibling);if(O.styleSheet){O.styleSheet.cssText=I}else{O.appendChild(z.createTextNode(I))}t.push(O)}}},q=function(A,C){var B=d();if(!B){return}B.open("GET",A,true);B.onreadystatechange=function(){if(B.readyState!=4||B.status!=200&&B.status!=304){return}C(B.responseText)};if(B.readyState==4){return}B.send(null)},d=(function(){var A=false;try{A=new XMLHttpRequest()}catch(B){A=new ActiveXObject("Microsoft.XMLHTTP")}return function(){return A}})();a();respond.update=a;function w(){m(true)}if(g.addEventListener){g.addEventListener("resize",w,false)}else{if(g.attachEvent){g.attachEvent("onresize",w)}}})(this);
380 test/respond.src.js
View
@@ -0,0 +1,380 @@
+/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
+/*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
+window.matchMedia = window.matchMedia || (function(doc, undefined){
+
+ var bool,
+ docElem = doc.documentElement,
+ refNode = docElem.firstElementChild || docElem.firstChild,
+ // fakeBody required for <FF4 when executed in <head>
+ 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 = '&shy;<style media="'+q+'"> #mq-test-1 { width: 42px; }</style>';
+
+ docElem.insertBefore(fakeBody, refNode);
+ bool = div.offsetWidth == 42;
+ docElem.removeChild(fakeBody);
+
+ return { matches: bool, media: q };
+ };
+
+})(document);
+
+
+
+/*! Respond.js v1.1.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */
+(function( win ){
+ //exposed namespace
+ win.respond = {};
+
+ //define update even in native-mq-supporting browsers, to avoid errors
+ respond.update = function(){};
+
+ //expose media query support flag for external use
+ respond.mediaQueriesSupported = win.matchMedia && win.matchMedia( "only all" ).matches;
+
+ //if media queries are supported, exit here
+ if( respond.mediaQueriesSupported ){ return; }
+
+ //define vars
+ 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" ),
+ $styles = $('style[type="text/css"]'),
+ requestQueue = [],
+ tm = null,
+ getDecimalValueByName = function( propValue, propName ){
+ var re = new RegExp("\\(" + propName + ":[\\s]*([\\s]*[0-9\\.]+)(px|em)[\\s]*\\)");
+ return (propValue.match( re ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ));
+ },
+
+ //loop stylesheets, send text content to translate
+ ripCSS = function(){
+ var sheets = links,
+ sl = sheets.length,
+ i = 0,
+ l,
+ elm,
+ //vars for loop:
+ sheet, href, media, isCSS,
+ inlineStyleContent;
+
+ for( ; i < sl; i++ ){
+ sheet = sheets[ i ],
+ href = sheet.href,
+ media = sheet.media,
+ isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet";
+
+ //only links plz and prevent re-parsing
+ 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 {
+
+ if( (!/^([a-zA-Z:]*\/\/)/.test( href ) && !base) || href.replace( RegExp.$1, "" ).split( "/" )[0] === win.location.host ){
+ requestQueue.push( {
+ href: href,
+ media: media
+ } );
+ }
+
+ }
+ }
+ }
+
+ for(i = 0, l = $styles.length; i < l; i++ ){
+ elm = $styles[i];
+ inlineStyleContent = elm.innerHTML || elm.innerText || elm.textContent;
+ if( inlineStyleContent ){
+
+ translate( inlineStyleContent );
+
+ }
+ }
+ makeRequests();
+ },
+
+ //recurse through request queue, get css text
+ makeRequests = function(){
+ if( requestQueue.length ){
+ var thisRequest = requestQueue.shift();
+
+ ajax( thisRequest.href, function( styles ){
+ translate( styles, thisRequest.href, thisRequest.media );
+ parsedSheets[ thisRequest.href ] = true;
+ makeRequests();
+ } );
+ }
+ },
+
+ //find media blocks in css text, convert to style blocks
+ translate = function( styles, href, media ){
+ href = 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( "/" )),
+ repUrls = function( css ){
+ return css.replace( /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g, "$1" + href + "$2$3" );
+ },
+ useMedia = !ql && media,
+ //vars used in loop
+ i = 0,
+ j, fullq, thisq, eachq, eql;
+
+ //if path exists, tack on trailing slash
+ if( href.length ){ href += "/"; }
+
+ //if no internal queries exist, but media attr does, use that
+ //note: this currently lacks support for situations where a media attr is specified on a link AND
+ //its associated stylesheet has internal CSS media queries.
+ //In those cases, the media attribute will currently be ignored.
+ if( useMedia ){
+ ql = 1;
+ }
+
+
+ for( ; i < ql; i++ ){
+ j = 0;
+
+ //media attr
+ if( useMedia ){
+ fullq = media;
+ rules.push( repUrls( styles ) );
+ }
+ //parse for styles
+ else{
+ fullq = qs[ i ].match( /@media *([^\{]+)\{([\S\s]+?)$/ ) && RegExp.$1;
+ rules.push( RegExp.$2 && repUrls( RegExp.$2 ) );
+ }
+
+ eachq = fullq.split( "," );
+ eql = eachq.length;
+
+ for( ; j < eql; j++ ){
+ thisq = eachq[ j ];
+ mediastyles.push( {
+ media : thisq.split( "(" )[ 0 ].match( /(only\s+)?([a-zA-Z]+)\s?/ ) && RegExp.$2 || "all",
+ rules : rules.length - 1,
+ hasquery: thisq.indexOf("(") > -1,
+ minw : getDecimalValueByName( thisq, 'min\-width' ),
+ maxw : getDecimalValueByName( thisq, 'max\-width' ),
+ minh : getDecimalValueByName( thisq, 'min\-height' ),
+ maxh : getDecimalValueByName( thisq, 'max\-height' )
+ } );
+ }
+ }
+
+ // It's fix for calling applyMedia once for all styles links
+ tm && window.clearTimeout( tm );
+ tm = window.setTimeout(function(){
+ applyMedia()
+ }, 50);
+ },
+
+ lastCall,
+
+ resizeDefer,
+
+ // returns the value of 1em in pixels
+ getEmValue = function() {
+ var ret,
+ div = doc.createElement('div'),
+ body = doc.body,
+ fakeUsed = false;
+
+ div.style.cssText = "position:absolute;font-size:1em;width:1em";
+
+ if( !body ){
+ body = fakeUsed = doc.createElement( "body" );
+ body.style.background = "none";
+ }
+
+ body.appendChild( div );
+
+ docElem.insertBefore( body, docElem.firstChild );
+
+ ret = div.offsetWidth;
+
+ if( fakeUsed ){
+ docElem.removeChild( body );
+ }
+ else {
+ body.removeChild( div );
+ }
+
+ //also update eminpx before returning
+ ret = eminpx = parseFloat(ret);
+
+ return ret;
+ },
+
+ getCSSRuleValue = function( rule ){
+ return parseFloat( rule ) * ( rule.indexOf( "em" ) > -1 ? ( eminpx || getEmValue() ) : 1 );
+ },
+
+ //cached container for 1em value, populated the first time it's needed
+ eminpx,
+
+ //enable/disable styles
+ applyMedia = function( fromResize ){
+ var nameW = "offsetWidth",
+ nameH = "offsetHeight",
+ docElemPropW = docElem[ nameW ],
+ docElemPropH = docElem[ nameH ],
+ currWidth = doc.compatMode === "CSS1Compat" && docElemPropW || doc.body[ nameW ] || docElemPropW,
+ currHeight = doc.compatMode === "CSS1Compat" && docElemPropH || doc.body[ nameH ] || docElemPropH,
+ styleBlocks = {},
+ lastLink = links[ links.length-1 ],
+ now = (new Date()).getTime(),
+ i = 0,
+ l = 0;
+
+ //throttle resize calls
+ if( fromResize && lastCall && now - lastCall < resizeThrottle ){
+ clearTimeout( resizeDefer );
+ resizeDefer = setTimeout( applyMedia, resizeThrottle );
+ return;
+ }
+ else {
+ lastCall = now;
+ }
+
+ for( i = 0, l = mediastyles.length; i < l; i++ ){
+
+ var thisstyle = mediastyles[ i ],
+ minw = thisstyle.minw,
+ maxw = thisstyle.maxw,
+ minh = thisstyle.minh,
+ maxh = thisstyle.maxh,
+ minwnull = minw === null,
+ maxwnull = maxw === null,
+ minhnull = minh === null,
+ maxhnull = maxh === null;
+
+ if( !minwnull ){
+ minw = getCSSRuleValue( minw );
+ }
+ if( !maxwnull ){
+ maxw = getCSSRuleValue( maxw );
+ }
+ if( !minhnull ){
+ minh = getCSSRuleValue( minh );
+ }
+ if( !maxhnull ){
+ maxh = getCSSRuleValue( maxh );
+ }
+
+ // if there's no media query at all (the () part), or min or max is not null, and if either is present, they're true
+ if( !thisstyle.hasquery ||
+ ( !minwnull || !maxwnull ) && ( minwnull || currWidth >= minw ) && ( maxwnull || currWidth <= maxw ) ||
+ ( !minhnull || !maxhnull ) && ( minhnull || currHeight >= minh ) && ( maxhnull || currHeight <= maxh )
+ ){
+ if( !styleBlocks[ thisstyle.media ] ){
+ styleBlocks[ thisstyle.media ] = [];
+ }
+ styleBlocks[ thisstyle.media ].push( rules[ thisstyle.rules ] );
+ }
+ }
+
+ //remove any existing respond style element(s)
+ for( i = 0, l = appendedEls.length; i < l; i++ ){
+ if( appendedEls[ i ] && appendedEls[ i ].parentNode === head ){
+ head.removeChild( appendedEls[ i ] );
+ }
+ }
+
+ //inject active styles, grouped by media type
+ for( var i in styleBlocks ){
+ if( styleBlocks.hasOwnProperty( i ) ){
+ var ss = doc.createElement( "style" ),
+ css = styleBlocks[ i ].join( "\n" );
+
+ ss.type = "text/css";
+ ss.media = i;
+
+ //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 ){
+ ss.styleSheet.cssText = css;
+ }
+ else {
+ ss.appendChild( doc.createTextNode( css ) );
+ }
+
+ //push to appendedEls to track for later removal
+ appendedEls.push( ss );
+ }
+ }
+ },
+ //tweaked Ajax functions from Quirksmode
+ 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 );
+ },
+ //define ajax obj
+ xmlHttp = (function() {
+ var xmlhttpmethod = false;
+ try {
+ xmlhttpmethod = new XMLHttpRequest();
+ }
+ catch( e ){
+ xmlhttpmethod = new ActiveXObject( "Microsoft.XMLHTTP" );
+ }
+ return function(){
+ return xmlhttpmethod;
+ };
+ })();
+
+ //translate CSS
+ ripCSS();
+
+ //expose update for re-running respond later on
+ respond.update = ripCSS;
+
+ //adjust on resize
+ function callMedia(){
+ applyMedia( true );
+ }
+ if( win.addEventListener ){
+ win.addEventListener( "resize", callMedia, false );
+ }
+ else if( win.attachEvent ){
+ win.attachEvent( "onresize", callMedia );
+ }
+})(this);
Something went wrong with that request. Please try again.