Selectivizr and Respond playing together

First off, this is NOT a production ready solution. This is a proof of concept. Selectivizr.js and Respond.js have both been hacked to make this work. More discussion, work and testing is required before this becomes practical for real-world use. I welcome any feedback and suggestions for improving this implementation. So, if you'd like to share, you can find me on twitter.

What's happening here?

This demo is using Respond to add media query support AND selectivizr to emulate CSS3 pseudo-class selectors in IE<9 at the same time. If you resize your browser window this page should change colour. Once you've done that, take look at the CSS (shown below) and you'll see that :nth-child is the hook providing the background colour change — A responsive web page styled with CSS3 selectors in IE<9.

body:nth-child(2) {
	background: #cfc;
	font: 14px/1.5 Arial;
}

h1:first-child {
	line-height:1.25;
	border-bottom:2px solid #333;
}
pre {
	background:#fff;
	padding:10px;
}
@media screen and (min-width: 500px) {
	body:nth-child(2) {
		background: #fcc;
	}
}
@media screen and (min-width: 800px) {
	body:nth-child(2) {
		background: #ccf;
	}
}	

How does it work?

A custom version of selectivizr 1.0.3b is exposing the selectiviz'd CSS text through an expando property (rawCssText) on every styleSheet object that has a valid URL. The rawCssText property is exposed by setting line 456 of selectivizr.js to:

stylesheet.cssText = stylesheet.rawCssText = patchStyleSheet( parseStyleSheet( url ) );

In addition to the exposing the new property, selectivizr's RE_SELECTOR_GROUP regular expression (defined on line line 76) needs to be updated to consume @media block opening statements:

var RE_SELECTOR_GROUP = /((?:^|(?:\s*})+)(?:\s*@media[^{]+{)?)\s*([^\{]*?[\[:][^{]+)/g;

Next, we need to prevent Respond from re-requesting style sheets and overwriting selectivizr's work. To do this, Respond needs to test for and use the new rawCssText property. This is achieved by inserting the following code at line 42 of the comment-free branch of Respond.js:

if ( isCSS && sheet.styleSheet.rawCssText && !parsedSheets[ href ] ) {
	translate( sheet.styleSheet.rawCssText, href, media );
	parsedSheets[ href ] = true;
}

Any caveats?

Selectivizr and Respond both have their caveats which are documented on their respective websites. These haven't changed as a result of these modifications.

The only difference between this modified version of selectivizr compared to previous releases is the script MUST be placed after all CSS <link>'s and selectivizr MUST also be included before Respond.

Finally

It works! In my opinion, using an expando property to expose CSS isn't ideal. Perhaps it would be better to have scripts test for each other via global object tests? Then again, they would all need to expose an API to access the underlying CSS. What do you think?

Thanks for reading. Discuss...

Keith Clark