Coder Social home page Coder Social logo

respond's Introduction

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

  • Licensed under the MIT license.

The goal of this script is to provide a fast and lightweight (3kb minified / 1kb gzipped) script to enable responsive web designs 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 and also here

Demo page (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
    @media screen and (min-width: 480px){
        /** ...styles for 480px and up go here **/
    }
  1. 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 un-media'd content)

  2. 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 set up a local proxy to request the CSS for old IE browsers. Prior versions recommended a deprecated x-domain approach, but a local proxy is preferable (for performance and security reasons) to attempting to work around the cross-domain limitations.

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 its 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 referenced 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.

  • If the request for the CSS file that includes MQ-specific styling is behind a redirect, Respond.js will fail silently. CSS files should respond with a 200 status.

  • 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.

  • If you have more than 32 stylesheets referenced, IE will throw an error, Invalid procedure call or argument. Concatenate your CSS and the issue should go away.

  • Sass/SCSS source maps are not supported; @media -sass-debug-info will break respond.js. Noted in issue #148

  • Internet Explorer 9 supports css3 media queries, but not within frames when the CSS containing the media query is in an external file (this appears to be a bug in IE9 โ€” see https://stackoverflow.com/questions/10316247/media-queries-fail-inside-ie9-iframe). See this commit for a fix if you're having this problem. https://github.com/NewSignature/Respond/commit/1c86c66075f0a2099451eb426702fc3540d2e603

  • Nested Media Queries are not supported

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.
  • respond.getEmValue() : returns the pixel value of one em

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 https://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! :)

respond's People

Contributors

akshayagarwal avatar alexanderdickson avatar amilajack avatar chimurai avatar chrisjacob avatar coridyn avatar cvrebert avatar darep avatar doctyper avatar drywall avatar eddiemonge avatar eikimart avatar elidupuis avatar glenveegee avatar hellolindsay avatar jefflembeck avatar johnalbin avatar keithclark avatar lencioni avatar mathiasbynens avatar meh-uk avatar paulirish avatar philipwalton avatar rcpeters avatar samkatakouzinos avatar scottjehl avatar seanxiesx avatar suriyaakudoisc avatar tomfuertes avatar zachleat avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

respond's Issues

Only external CSS files work?

In order to make things work for IE I needed to create external stylesheets. It's not possible to use <style> ? Or any other work around in order to avoid multiple http requests for the css files?

"screen and"

Using on new design of http://css-tricks.com/ ...

Did not work with my media queries like

@media (max-width: 1200px)

but if I added "screen and" it works

@media screen and (max-width: 1200px)

May be expected behavior but had me stumped for a minute. If it was up to me I wouldn't use screen and and just let the media query handle all media types.

IE7 not responding to child combinator ('>') when inside media query

Howdy Scott!

Not sure if this is something related specifically to respond.js or if it's a general issue w/ IE7.

IE7 has support for child combinators (element > element { styles here}), and seems to understand them well when I have them outside of the media queries, but any rules with combinators in media queries IE7 seems to ignore completely and I can only get it to understand the styles if I just use descendent selectors (I'd rather use the combinators because it'll eliminate the need for a bunch of arbitrary classes).

IE8 seems to understand the combinators just fine.

I'm still doing some testing, but I was wondering if you have happen to come across any similar issues while developing respond.js.

Thanks!

And thanks for your work on respond.js.

Best,

Diego

@import support?

(Poet, know it.)

This is a random thought, and probably out of scope, but I wonder if Respond.js could be extended to handle media queries inside @import rules. For example:

@import url(dashboard.css) screen and (min-width: 960px);/*/mediaquery*/

In the above example, dashboard.css would only load in screens wider than 960px.

This would probably bring up a whole host of issuesโ€”nested @imports, ensuring @imported styles maintain their rank in the cascade, &c.โ€”and is probably out of scope for this script anyway. Still, thought itโ€™d be worth asking!

Favicon link breaks media queries in IE8

Adding a favicon link tag to the html head breaks media queries in IE8. E.g.

I tested it by downloading your demo page and associated files and added a favicon link. It may also affect other versions of IE, I haven't had a chance to test them yet.

Looking at your ripCSS function it appears you are treating all link tags with an href as stylesheets.

When you loop over the stylesheets and test to see if the link has an href (line 43) you should also test to see if it is a stylesheet. e.g.
if( !!href && !parsedSheets[ href ] && (!rel || rel.indexOf("stylesheet") != -1) && (!type || type == 'text/css')){

Consider a non-comment way to detect media query

It would be great to have a non-comment way to detect media queries because

  • They will get stripped out when minifying.
  • It is difficult to correctly place them after the query with no line break when using compass.

Line 115 (em support branch): 'null' is null or not an object (only appears with concatenated CSS)

The script doesn't throw any errors when I load in my three separate CSS files separately:

http://dev.paulrobertlloyd.com/about/

However, when using concatenated CSS files (compressed using PHP Minify), I get the following error:

'null' is null or not an object, line 115, character 5

Here's a link to the CSS file I'm loading, and the page where this CSS is being called from:

http://dev.paulrobertlloyd.com/_php/min/?g=css&1313442539
http://dev.paulrobertlloyd.com/about/styleguide/

Line 145 (em support branch): 'Body is undefined'

I ran into several errors when using the em support script in IE8. After doing some debugging with Andy Hume, we determined that 'body.currentStyle.fontSize' on line 145 should actually be 'doc.body.currentStyle.fontSize'. This resolves the error.

[attr=] selectors not working

Weird one this, I think I have narrowed it down to respond.js. (Sorry if this has been covered elsewhere)

Basically, I have a HTML5 page set up using ARIA roles, such as header[role=banner], nav[role=navigation], div[role=main] etc. My CSS is split into separate CSS files using linked media queries to make it easier during development (based on Andy Clarke's 320 and up), although as long as file size doesn't take too much of a hit I will probably consolidate into one file with the media queries inside.

Anyway, taking the header[role=banner] h1 element as an example I can successfully style it in my style.css file that loads regardless of screen size using:

header[role=banner] h1 {
text-transform: lowercase;
}

However, in a stylesheet linked depending on a media query such as 768.css:

header[role=banner] h1 {
text-transform: uppercase;
}

Refuses to work, but without the [role=banner] attribute selector it would work as expected.

I can't link to the page I am working on, but I will throw together an example later when I get a chance to see if anyone can help me narrow the problem further.

Not working in Firefox 3.0.6

A client let us know that the site wasn't 'responding' in FF 3.0.6. I noticed the bug you fixed in the latest update, and so updated my local copy. The error no longer appears, but the script just doesn't seem to be doing anything. I'm testing this on FF 3.0.6 with firebug 1.4.4

I'll keep digging and see if I can come up with anything of help in the meantime.

Fails if the string @media appears in a comment

The styles in an @media block don't get applied if the string '@media' appears in a comment within the @media block (not sure about if it appears between blocks). I know it's an edge case, but I usually include @media in a comment this to mark the closing } of the MQ! The experimental parser didn't experience this issue.

IE8 gives access denied error

CSS, js and site are all in the same domain, and there is no imported CSS. The only media queries are at the end of the CSS file and are as follows:

@media only screen and (min-width: 1164px){
.menu-main-container li{display:inline;position:relative;list-style:none;margin: 0 2.6%}
}//mediaquery/

@media only screen and (max-width: 1088px){
.feature.right{padding-right:200px}
}//mediaquery/

The error message is as follows (domain is removed):

Message: Access is denied.

Line: 7
Char: 1736
Code: 0
URI: http://******.com/js/respond.min.js

Style blocks should be ordered by query expression, not media type

I stumbled onto a bug that results from the way Respond groups style blocks by media type instead of by query expression, i.e. "(min-width: 900px)".

For (a silly) example, say I want to apply a white background to all media types at a min-width of 1000px, and I want to display a background image only if it's on screen at a min-width of 1600px:
@media all and (min-width: 1000px) { body { background: white; } } @media screen and (min-width: 1600px) { body { background: black url("image.jpg"); } }

Because the styles are grouped by media type, at 1600px the "screen" block is injected, followed by the "all" block and the background image definition is overridden. Yes, this is a contrived example, but browsers that support media queries handle it correctly and as expected.

I've been giving it some thought and so far haven't come up with an efficient way to inject the styles correctly. Will keep thinking.

Versioning

Might be useful to start versioning Respond.js (and including the version in the copyright header). Bonus: git tags!

Also, Respond.js version information should be available in the Modernizr build (in a comment?).

Idea - API to request / fake / force media query

This doesn't really fit respond.js core purpose but I think could be really useful for testing.

Basically an API to request / fake / force a media query... From JavaScript.

Respond.js already has everything it needs to make this happen by loading in the CSS via AJAX and injecting it onto the page.

My use case is that I want a control on my page to allow users to choose a "layout" width... E.g. 320, 480, 768, 1024, 1280 etc...

E.g. If I'm on my iPhone media queries will enforce a 320px in portrait... But I want to give user ability to overwrite this e.g. "view normal layout" (1024px).

Also perfect for testing your resonsive designs without manually needing to resize the browser window. E.g. I want to put a button on my page while building a site that when I click it it opens a new tab for each width I'm supporting for the site...even widths larger then the screen size I have available like 1920. Obvious I'll do this new tab launching with some JavaScript. The idea is to have a fragment like #px=1024 I will check this and pass it into respond.js API call.

... Perhaps more suited as a fork of this project... Dictate.js :-p

Iterested to hear your thoughts.

Make some unit tests, man

Simply checking if this thing renders the Globe site properly doesn't mean everything's covered...

...talking to myself.

Error: 'nextSibling' is null or not an object

I've tried Respond in IETester in IE 6, 7, and 8 and also in IE6 in a fresh XP Mode Virtual PC. All of them give me the error mentioned in the title on line 195 (the only use of nextSibling). The error occurs on resize, not on initial load.

Am I missing something obvious?

Cross-domain patch pretty please!

I am trying to use the 320 and Up boilerplate on a Shopify store, where all .css and .js files get served from a subdomain of myshopify.com rather than the store's domain.

So, I would love to see this patched.

Thanks in advance!

Layout remains unresponsive (em support branch)

I've been testing this script on the following page on IE8: http://dev.paulrobertlloyd.com/about/ The layout of this page is controlled with em-based media quieries.

The basic layout seems to be honoured, but other CSS rules seem to be ignored; for example the main image isn't resized to 106%, and the layout around the footer remains linearised.

On resize, none of the elements reposition as intended; for example the sidebar move above the main content area when the page narrows. Compare this page in IE8 to how it works on other browsers.

:first-child not recognized by IE6/7

@media screen and (min-width: 768px) { /* 10-Zoll Tablets, bspw. iPad, im Portrait-Mode */
#header .primary :first-child {
background:none;
}
}

This ain't working in IE6 and 7, outside of the media query, it does work.

Background Color does not show up in IE6/7

@media screen and (min-width: 768px) { /* 10-Zoll Tablets, bspw. iPad, im Portrait-Mode */
.fullheightimage {
display: block;
}

.primary li {
    width: auto;
}

.primary a {
    background: #6A94A0;
    background: -moz-linear-gradient(top, rgba(163,186,196,1) 0%, rgba(160,184,195,1) 50%, rgba(138,167,180,1) 51%, rgba(138,167,180,1) 100%);
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(163,186,196,1)), color-stop(50%,rgba(160,184,195,1)), color-stop(51%,rgba(138,167,180,1)), color-stop(100%,rgba(138,167,180,1)));
    background: -webkit-linear-gradient(top, rgba(163,186,196,1) 0%,rgba(160,184,195,1) 50%,rgba(138,167,180,1) 51%,rgba(138,167,180,1) 100%);
    background: -o-linear-gradient(top, rgba(163,186,196,1) 0%,rgba(160,184,195,1) 50%,rgba(138,167,180,1) 51%,rgba(138,167,180,1) 100%);
    background: -ms-linear-gradient(top, rgba(163,186,196,1) 0%,rgba(160,184,195,1) 50%,rgba(138,167,180,1) 51%,rgba(138,167,180,1) 100%);
    background: linear-gradient(top, rgba(163,186,196,1) 0%,rgba(160,184,195,1) 50%,rgba(138,167,180,1) 51%,rgba(138,167,180,1) 100%);
}

}

.primary a should show a blue background, but it doesn't. If the same code is placed outside of the media query, it works properly. I need to add

.ie6 .primary a, .ie7 .primary a, .ie8 .primary a, .ie9 .primary a {
    background: #6A94A0;
}

inside the media query, to make it work. Looks like a bug to me. Doesn't matter if I use the "pure" respond.min.js or the respond included in modernizr.

Live:

http://svn.taquiri.de/niedrigenergiepool/branches/respond-bug/

Breaks in IE when sourcing multiple stylesheets

After trying to figure out what was breaking Respond in IE, all day, I finally started deleting styles and culling stuff down to debug. Finally ended up removing one of the two stylesheets, and it works. Even if I put a single style, or even leave blank, a second CSS and source it in, Respond breaks. Is there a reason for this? Is there now way to work on a site with multiple CSS docs and use Respond?

Thanks,
Logan

req: retrieve active media-queries through javascript

Not sure if this is the correct place for a feature request, but here it goes anyway:

Respond.js works great for bringing browser-independent support for media-queries.
However, when experimenting with responsive design I sometimes have the need to structure the DOM just a bit differently (using javascript) to achieve what I want (in addition to css-styling with media queries)

For this to work cross-browser too, to me the ideal situation would be to be able to request in javascript which media-queries are currently 'active' .

Modernizr.js for example has the mq() function which enables to ask for 'active' media-queries, but fails for IE8 and smaller for obvious reasons. I feel this feature would perfectly fit within Respond.js.

What do you think?

Thanks,
Geert-Jan

Using respond.js with yepnope seems to break Opera

When using respond.js in conjunction with yepnope.js, I'm seeing an issue with Opera where the <body> of the page is not getting the background-color specified in the CSS following the enclosed <div id="container">. If I do not use yepnope and just include respond.js unconditionally, the problem goes away. So, I'm not sure if this is more of a problem with yepnope or respond, as respond is the only script I've seen have any behavior like this. I've included a basic HTML doc that demonstrates the problem.

<!doctype html>
<html class="no-js" lang="en">
<head>
    <meta charset="utf-8">
    <title></title>

    <style>
    body {
      min-width: 960px;
      background-color: #f2f2f2;
    }

    #container {
      width: 960px;
      margin: 0 auto;
      padding: 5em;
      border: 1px solid #ddd;
      background-color: #fff;
    }
    </style>

    <script src="modernizr-1.8pre.min.js"></script>
    <script src="yepnope.min.js"></script>
    <!-- <script src="respond.min.js"></script> -->

    <script>
    yepnope({
      test: Modernizr.mq('(min-width)'),
      nope: 'respond.min.js'
    });
    </script>
</head>

<body>
    <div id="container">
    </div>
</body>
</html>

@media screen vs @media ?

My media queries using just @media work great in webkit. But this script does not recognize them? Using @media screen the script works brilliantly in IE, but my queries do not work in webkit. Am I doing something drastically wrong?

Parser stops processing current media-query when running into an empty rule

Example code:

@media only screen and (min-width: 768px) {

.some_class {}
body {background: red;}

}

@media only screen and (min-width: 992px) {

body {background: green;}

}

When running into the empty rule in the first block, parser immediately jumps to the next block ignoring remaining rules in the first block. I've realized it could be easily fixed by adding an extra space into that empty rule โ€“ย { } (or removing empty rules completely, indeed).

It really isn't too critical as empty rules don't have any function in our stylesheets, but I haven't found any mention of this bug and it took me a noticeable amount of time to find it so I think it would be great at least to mention that in the documentation.

Thanks for a great plugin, keep the good work!

Breaks in IE7 & 8 with WP Minify (CSS minification)

I've downloaded the latest version of respond.js but whenever I use the WP Minify plugin with CSS minification, media queries don't seem to work in IE7 & 8.

I've also read through the comments in this issue #12 and thought that respond.js no longer needed CSS comment tokens to mark the end of a media query statement? Is there something I'm missing?

Ensure that a throttled resize event will still fire

Currently, the resize event handler is throttled to only fire every 50ms, but the logic doesn't ensure that the last call will execute, assuming another one doesn't come along. I'm not seeing many issues with this yet, but it'll likely crop up in layouts with many breakpoints.

Hard crash

Hi,

I've experienced a big crash on IE6-8 standalone versions with your last sources (04/19) ^^

null is null or not an object

Hi,

This script is great and was working fine until I use google minify for other js.

My code is like this:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script> <script src="/min/g=js&3"></script> <script> yepnope.errorTimeout = 2000; Modernizr.load([ { test : Modernizr.mq(), nope : 'scripts/respond.min.js' }, { load: ['ielt9!scripts/selectivizr-min.js'] } ]); </script>

Now if i dont use google minify before the inline script it works great, but if i do use google minify I get the error:

null is null or not an object
line 112 char 5

I really want to continue using google minify AND respond.js. Any ideas whats going on?

Cheers,
Adi

Firefox 3.0.11 error: uncaught exception: [Exception... "Not enough arguments [nsIXMLHttpRequest.send]"

Full error:

uncaught exception: [Exception... "Not enough arguments [nsIXMLHttpRequest.send]"  nsresult: "0x80570001 (NS_ERROR_XPC_NOT_ENOUGH_ARGS)"  location: "JS frame :: http://localhost:8888/sites/all/themes/test/scripts/respond.min.js :: anonymous :: line 210"  data: no]

Setting line 210:

req.send();

to:

req.send(null);

fixes this particular issue.

Only bug I could find:
https://bugzilla.mozilla.org/show_bug.cgi?id=448300

Here's the version respond.src.js I was using when this error happened (should be the latest) for reference:

/*! Respond.js: min/max-width media query polyfill. (c) Scott Jehl. MIT Lic. j.mp/respondjs  */
(function( win, mqSupported ){
    //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   = mqSupported;

    //if media queries are supported, exit here
    if( mqSupported ){ return; }

    //define vars
    var doc             = win.document,
        docElem         = doc.documentElement,
        mediastyles     = [],
        rules           = [],
        appendedEls     = [],
        parsedSheets    = {},
        resizeThrottle  = 30,
        head            = doc.getElementsByTagName( "head" )[0] || docElem,
        links           = head.getElementsByTagName( "link" ),
        requestQueue    = [],

        //loop stylesheets, send text content to translate
        ripCSS          = function(){
            var sheets  = links,
                sl      = sheets.length,
                i       = 0,
                //vars for loop:
                sheet, href, media, isCSS;

            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 ] ){
                    if( !/^([a-zA-Z]+?:(\/\/)?)/.test( href ) 
                        || href.replace( RegExp.$1, "" ).split( "/" )[0] === win.location.host ){
                        requestQueue.push( {
                            href: href,
                            media: media
                        } );
                    }
                    else{
                        parsedSheets[ href ] = true;
                    }   
                }
            }
            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 ){
            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.match( /(only\s+)?([a-zA-Z]+)(\sand)?/ ) && RegExp.$2,
                        rules   : rules.length - 1,
                        minw    : thisq.match( /\(min\-width:[\s]*([\s]*[0-9]+)px[\s]*\)/ ) && parseFloat( RegExp.$1 ), 
                        maxw    : thisq.match( /\(max\-width:[\s]*([\s]*[0-9]+)px[\s]*\)/ ) && parseFloat( RegExp.$1 )
                    } );
                }   
            }

            applyMedia();
        },

        lastCall,

        resizeDefer,

        //enable/disable styles
        applyMedia          = function( fromResize ){
            var name        = "clientWidth",
                docElemProp = docElem[ name ],
                currWidth   = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[ name ] || docElemProp,
                styleBlocks = {},
                dFrag       = doc.createDocumentFragment(),
                lastLink    = links[ links.length-1 ],
                now         = (new Date()).getTime();

            //throttle resize calls 
            if( fromResize && lastCall && now - lastCall < resizeThrottle ){
                clearTimeout( resizeDefer );
                resizeDefer = setTimeout( applyMedia, resizeThrottle );
                return;
            }
            else {
                lastCall    = now;
            }

            for( var i in mediastyles ){
                var thisstyle = mediastyles[ i ];
                if( !thisstyle.minw && !thisstyle.maxw || 
                    ( !thisstyle.minw || thisstyle.minw && currWidth >= thisstyle.minw ) && 
                    (!thisstyle.maxw || thisstyle.maxw && currWidth <= thisstyle.maxw ) ){                      
                        if( !styleBlocks[ thisstyle.media ] ){
                            styleBlocks[ thisstyle.media ] = [];
                        }
                        styleBlocks[ thisstyle.media ].push( rules[ thisstyle.rules ] );
                }
            }

            //remove any existing respond style element(s)
            for( var i in appendedEls ){
                if( appendedEls[ i ] && appendedEls[ i ].parentNode === head ){
                    head.removeChild( appendedEls[ i ] );
                }
            }

            //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;

                if ( ss.styleSheet ){ 
                    ss.styleSheet.cssText = css;
                } 
                else {
                    ss.appendChild( doc.createTextNode( css ) );
                }
                dFrag.appendChild( ss );
                appendedEls.push( ss );
            }

            //append to DOM at once
            head.insertBefore( dFrag, lastLink.nextSibling );
        },
        //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();
        },
        //define ajax obj 
        xmlHttp = (function() {
            var xmlhttpmethod = false,
                attempts = [
                    function(){ return new ActiveXObject("Microsoft.XMLHTTP") },
                    function(){ return new XMLHttpRequest() }       
                ],
                al = attempts.length;

            while( al-- ){
                try {
                    xmlhttpmethod = attempts[ al ]();
                }
                catch(e) {
                    continue;
                }
                break;
            }
            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,
    (function( win ){

        //for speed, flag browsers with window.matchMedia support and IE 9 as supported
        if( win.matchMedia ){ return true; }

        var bool,
            doc         = document,
            docElem     = doc.documentElement,
            refNode     = docElem.firstElementChild || docElem.firstChild,
            // fakeBody required for <FF4 when executed in <head>
            fakeUsed    = !doc.body,
            fakeBody    = doc.body || doc.createElement( "body" ),
            div         = doc.createElement( "div" ),
            q           = "only all";

        div.id = "mq-test-1";
        div.style.cssText = "position:absolute;top:-99em";
        fakeBody.appendChild( div );

        div.innerHTML = '_<style media="'+q+'"> #mq-test-1 { width: 9px; }</style>';
        if( fakeUsed ){
            docElem.insertBefore( fakeBody, refNode );
        }   
        div.removeChild( div.firstChild );
        bool = div.offsetWidth == 9;  
        if( fakeUsed ){
            docElem.removeChild( fakeBody );
        }   
        else{
            fakeBody.removeChild( div );
        }
        return bool;
    })( this )
);

Can't use in IE8

I'm using the latest version of boilerplate html5 wich includes respond.js and in IE8 the browser just crashes after loading the page.
Removing it works (doesn't crash but of course media queries don't work either).
Any advice?

Thank you!

Need a Demo link

respond.js looks awesome from what you've written in the README ... but am I blind or is there no link provided to a DEMO?

When I download the files and try to run on my local machine IE8 won't run the scripts.

I also tried to setup a demo on jsfiddle.net ... but cross domain limitation apply.

Would be great if you could setup a Github Pages branch with a demo on it.

  • Chris

Mobile Filesize = Great, Older Mobile Performance = ?

Hi Scott,

1st, thanks for this brilliant script!

2nd, I'm curious how respond.js performs on older mobile phones (infact more so then how it handles ie6-8 ...which I'm sure is very well). Personally I don't own any old mobile phones, nor do I have the resources to get my hands on any.... But I suspect you might.

My scenario is that for browsers that don't natively support media queries they get a "basic.css" stylesheet (ie6-8, older mobiles, etc). Its a single column layout, and desktop browsers will hit a max-width 720px, keeping everything nicely contained for ie6-8. It's less likely that their browser window will be <720px.... So my main target audience for running respond.js is older mobile devices.

Ideally I would like to use media queries in my basic.css, and "cascade" / progressively enhance upwards to a second stylesheet - advanced.css for modern browsers ...

An alternative to respond.js+media queries is to run use JavaScript to append min-width-x class attributes to the root element... Then use something like .min-width-480 In basic.CSS ... But classes like this don't cascade very well upwards into advanced.CSS - which is given to users with known media query support.

Respond.js's file size & framework independence is perfect. But I wonder how well the performance is on older mobiles ...with ajax getting the css, then js parsing and injecting Dom elements?

Thanks in advance for any insight / feedback you're able to offer.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.