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

百般思念 提交于 2019-12-04 13:03:09
Arnaud Le Blanc

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

Don't use innerHTML, use document.createTextNode() and your life will become infinitely better ;)

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

EDIT:

Since this solution doesn't seem to work for you, I'd abandon it. Instead go for a solution where styles are already defined and where you just disabled/enable styles via javascript if available.

You can do it this way:

<head>
<style>
.jsenabled #div2, #div1 { display: none;}
.jsenabled #div1, #div2 { display: block;}
</style>
<script>
//i know you don't use jQuery, but the solution should still be valid as a concept
//bind to DOM-ready, then set the class jsenabled on the body tag
$(function() {
 $(document.body).addClass('jsenabled');
});
</script>
</head>
<body>
<div id="div1">div 1 (should be shown if JS enabled)</div>
<div id="div2">div 2 (should be hidden if JS enabled)</div>
</body>

EDIT 2:

If it has to be done prior to DOM ready, you could do something kinda ugly like this:

<head>
<style>
#div2, .show { display: block;}
#div1, .hide { display: none;}
</style>
</head>
<body>
<div class="hide">
<script>document.write('</div><div id="div1">');</script>
   div 1 (should be shown if JS enabled)
</div>
<script>document.write('<div class="hide">');</script>
<div id="div2">div 2 (should be hidden if JS enabled)</div>
<script>document.write('</div>');</script>
</body>

Or to keep things simple, you could just do

<head>
<script>document.write('<style>#div1 {display: block;} #div2 {display: none;}</style>');
</head>
<body>
<div id="div1">div 1 (should be shown if JS enabled)</div>
<div id="div2">div 2 (should be hidden if JS enabled)</div>
</body>

Best practice is to put all the <link for CSS into the <head, and most <script at tne very end of the <body (except short fragments of <script that should execute ASAP should go in the <head). Both the standard and browsers allow you to do silly things, but just because it's acceptable doesn't mean it's a good idea.

Rather than go through all the rigamarole of creating a Style node and of manipulating the DOM (which just provide more opportunities for something to go wrong), I recommend a much simpler solution. Hard code as much as you can into your document (and style sheet?) in advance once (rather than creating things on the fly every time). Here's a rough example:

<body ...
...
<div id="warning" style="display: block;">
JS is required for this site, but isn't available ...
</div>
<div id="message" style="display: none;">
JS is available
</div>
...

<script ...
var warningEl = document.getElementById('warning');
warningEl.style.display = 'none';
var messageEl = document.getElementById('message');
messageEl.style.display = 'block';
</script ...

This should work reasonably well most of the time (it will certainly work in more browsers than what you tried to do initially). However, any attempt to change the DOM in any way before the page is initially displayed to the user is not guaranteed to work (in other words neither your way nor the example above will always work in all cases). The earlier you run your Javascript, the more likely DOM operations (including getElementById) may fail. And the later you run your Javascript, the more likely the user will notice a perceptible "flicker" of their display. So you're presented with a tradeoff choice between wide compatibility and noticeable flicker.

You can wait until the DOM is guaranteed to be fully ready before you run your Javascript ("ready" in jQuery, or addEventListener 'domcontextloaded', or even addEventListener 'load'). This is guaranteed to function correctly in all cases. But it will flicker (perhaps quite badly) in many cases.

The only way I know (but I hope somebody else knows more:-) to avoid entirely the possibility of flicker is to put in the <head a fragment of Javascript that changes window.location but does nothing else. (No references to the DOM, which are usually made obvious by the word "document" somewhere in the code.) The net effect if JS is available will be an immediate reload of a different page before much of anything is shown to the user. The initial page can contain your warning, and the new page the real stuff with no warning.

Even this method has some disadvantages though: First, the double download takes extra bandwidth and delays user visibility a little. This won't matter on typical desktops. But on handhelds it may not be acceptable. And second, it will raise havoc with SEO. The second page -that's supposed to be invisible and only accessed from the first page- may show up independently in webdexes so users can easily access it directly (you may be able to "fix" this with clever use of "canonical" and/or "meta...robots"). And the SERP of the initial page may fall precipitously when its only content is the warning message.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!