Creating Style Node, adding innerHTML, add to DOM, and IE headaches

DA. picture DA. · Mar 8, 2011 · Viewed 10.9k times · Source

I have a two part question.

First, the scenario:

Due to some bizarre issues we've run into in regards to mobile browser support for NOSCRIPT, I'm tasked with coming up with an alternative solution to 'detect' JS. The solution logic is to have two DIVs on the page. One is an error stating you do not have JS and his shown by default. If one has JS, we then want to add a new STYLE block to the HEAD that over-rides the previous CSS and hides the error and instead shows the content.

The sample HTML:

<div id="div1">div 1 (should be shown if JS enabled)</div>
<div id="div2">div 2 (should be hidden if JS enabled)</div>

This is the JS I started with:

  var styleNode = document.createElement('style');
  styleNode.setAttribute("type", "text/css");
  styleNode.innerHTML = "#div1 {display: block;} #div2 {display: none;}";
  headTag.appendChild(styleNode);

But, I was having problems. Some googling resulting in this description of a security issue that IE can have if you try to insert innerHTML into a created element before placing it in the DOM:

http://karma.nucleuscms.org/item/101

So, I modified the script as such:

  var styleNode = document.createElement('style');
  styleNode.setAttribute("type", "text/css");
  var headTag = document.getElementsByTagName("head")[0];
  headTag.appendChild(styleNode);
  var aStyleTags = headTag.getElementsByTagName("style");
  var justAddedStyleTag = aStyleTags[aStyleTags.length-1];
  justAddedStyleTag.innerHTML = "#div1 {display: block;} #div2 {display: none;}";

question 1: is that a valid workaround for the IE issue? Is there a more efficient solution?

question 2: even with the adjustment, the script still does not work in IE. It works fine in Firefox, but in IE 7 I get an "unknown runtime error".

I have a sample of this code up on JSBIN:

http://jsbin.com/ucesi4/4

Anyone know what's going on with IE?

UPDATE:

I stumbled upon this link via google. Note the last comment:

http://msdn.microsoft.com/en-us/library/ms533897%28VS.85%29.aspx

That said, you really should put all style rules in the HEAD for strict compliance with XHTML. Doing this can also be a little tricky because you cannot use innerHTML to inject into the HEAD or STYLE element directly. (Both of these tags are READ ONLY.)

Eep! True? Is FireFox just being overly forgiving? Or is this just a very odd IE quirk?

UPDATE 2:

A bit more background on what we're trying to solve here. We're dealing with mobile devices and some of the antiquated devices a) don't support NOSCRIPT and b) have slow JS engines.

Since they don't support NOSCRIPT, we are by default showing an error, then hiding it via JS if they have it, and presenting them with the proper content. Because of the slow JS engines on these, people see the 'flicker' of the DIV's showing/hiding. This was the proposed solution to handle that, as it would load the CSS before the DIVs were even rendered.

Since it appears to be invalid, the solution will be that on these old devices, we'll use this method (as it seems to work, even if not in IE) and then all other proper browsers will do as suggested...we'll just update the DISPLAY CSS property via inline JS after each DIV is loaded in the DOM.

All that said, I'm still curious as to whether this issue is an IE bug, or if IE is actually adhering to the proper standards by making STYLE a read-only element.

Answer

Arnaud Le Blanc picture Arnaud Le Blanc · Sep 4, 2011

In IE you can use style.styleSheet.cssText:

var style = document.createElement('style');
style.type = 'text/css';

if (style.styleSheet) { // IE
    style.styleSheet.cssText = css;
} else {
    style.appendChild(document.createTextNode(css));
}

document.getElementsByTagName('head')[0].appendChild(style);

Try this here: http://jsfiddle.net/QqF77/

See the answer on this question: How to create a <style> tag with Javascript