I am currently trying to make my own polyfill that will allow older browsers such as Internet Explorer the ability to read and execute media queries using traditional css selectors. The process flow goes something like this:
- Iterate through each stylesheet found within document
- Run through each style rule in stylesheet searching for media queries
- Define what device size we are targeting then apply appropriate "id"
- Dynamically add css line with selector to existing stylesheet
The idea is that the polyfill will search for media queries then apply a parent "id" to the body corresponding to the device size, for instance:
#tablet .wrap { ... }
#mobile .wrap { ... }
#desktop .wrap { ... }
Here is what the javascript looks like so far:
var styleSheets = document.styleSheets;
var debug = false;
var ruleParts = mediaPart = rules = compiledSel = className = '';
var dimS = dimB = 0;
var idList = Array('smallMobile','mobile','tablet','smallDesktop','desktop');
// run through each stylesheet
for( i = 0; i < styleSheets.length; i++ ) {
// If uncommented will show each stylesheets rules contained therein
if( debug ) {
console.log( styleSheets[i].cssRules );
}
// run through each rule declaration
for( a = 0; a < styleSheets[i].rules.length; a++ ) {
if( styleSheets[i].rules[a].type == 4 ) {
mediaPart = styleSheets[i].rules[a].media[0].split(' and ');
dimS = parseInt( mediaPart[0].replace(/[():A-Za-z$-]/g, "") );
dimB = parseInt( mediaPart[1].replace(/[():A-Za-z$-]/g, "") );
if( dimS > 0 && dimB < 418 ) {
className = idList[0];
} else if( dimS > 419 && dimB < 767 ) {
className = idList[1];
} else if( dimS > 768 && dimB < 1024 ) {
className = idList[2];
} else if( dimS > 1025 && dimB < 1201 ) {
className = idList[3];
} else {
className = idList[4];
}
if( styleSheets[i].rules[a].cssRules.length > 1 ) {
for( b = 0; b < styleSheets[i].rules[a].cssRules.length; b++ ) {
ruleParts = styleSheets[i].rules[a].cssRules[b].cssText.split('{');
rules = ruleParts[1].split('}');
addCSSRule( styleSheets[i], '#'+ className +' '+ ruleParts[0], rules[0], 1 );
/*
* Investigate why the .insertRule() and addRule() are failing specifically what is causing them to break
*
*/
}
} else {
}
}
}
}
function addCSSRule(sheet, selector, rules, index) {
if(sheet.insertRule) {
sheet.insertRule(selector + "{" + rules + "}", index);
} else {
sheet.addRule(selector, rules, index);
}
}
Right now everything is working the way I want, even adding the css rule to the style sheet however I get this error and I'm not totally sure at what point:
Uncaught TypeError: Cannot read property 'length' of undefined
If I remove the function call to this line, I don't get the error:
addCSSRule( styleSheets[i], '#'+ className +' '+ ruleParts[0], rules[0], 1 );
So I'm not sure what is happening during the function call and the reading of the .length
My html looks something like this:
<!DOCTYPE html>
<head>
<title>Style Manipulation VIA Javascript</title>
<link rel="stylesheet" href="css/test.css" />
<link rel="stylesheet" href="css/typo.css" />
</head>
<body>
<div class="wrap">
<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis. Praesent dapibus, neque id cursus faucibus, tortor neque egestas augue, eu vulputate magna eros eu erat. Aliquam erat volutpat. Nam dui mi, tincidunt quis, accumsan porttitor, facilisis luctus, metus</p>
<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis. Praesent dapibus, neque id cursus faucibus, tortor neque egestas augue, eu vulputate magna eros eu erat. Aliquam erat volutpat. Nam dui mi, tincidunt quis, accumsan porttitor, facilisis luctus, metus</p>
</div>
Overall I need to figure out why the property length can't be read and what in the addCSSRule
function call is causing the error.
There are significant differences between the IE and W3C implementations of the styleSheets object, hopefully the following is explanatory enough to help:
There is documentation on MSDN of the IE model, but I'm not sure if it still covers older IE or only the newer versions which may well use both models: styleSheet object, rule object
There is some Opera documentation here: Dynamic style - manipulating CSS with JavaScript
and also some information here: The styleSheet object, The CSS Rule object.
As with all web resources, take it with a serious amount of skepticism, look for other sources and test, test, test in as many browsers (especially older ones) as you can.
Running your code:
Here you are mixing the IE (rules) and W3C (cssRules) models. Better to just get the rules object once: -
Then you have:
but the IE model doesn't implement a type property for the rules object (even though the MSDN documentation says it does, that's for the W3C model implemented by IE 9 and later).
Then:
Note that media is a property of the sheet, not of a rule, so:
And just to be nasty, the IE model has a media property with a type of string, but it's empty. You can get the text of it using:
.
Here you seem to be expecting "and" to be in the rule. You haven't provided an example of your rules, but if they are like:
then media is a list of the media rules:
media[0]
is screen andmedia[1]
is print, so you want to iterate over the media rules.Anyhow, that's enough for now.