我有两个问题。
首先,情景:
由于我们在NOSCRIPT的移动浏览器支持方面遇到了一些奇怪的问题,我的任务是提出另一种“检测”JS的解决方案。解决方案逻辑是在页面上有两个DIV。一个是错误,表明你没有JS和他默认显示。如果有一个JS,我们想要向HEAD添加一个新的STYLE块,它会覆盖以前的CSS并隐藏错误,而是显示内容。
示例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>
这是我开始使用的JS:
var styleNode = document.createElement('style');
styleNode.setAttribute("type", "text/css");
styleNode.innerHTML = "#div1 {display: block;} #div2 {display: none;}";
headTag.appendChild(styleNode);
但是,我遇到了问题。一些谷歌搜索导致IE可以具有的安全问题的描述,如果您尝试在将innerHTML放入创建的元素之前将其插入到DOM中:
http://karma.nucleuscms.org/item/101
所以,我修改了脚本:
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;}";
问题1 :这是IE问题的有效解决方法吗?有更有效的解决方案吗?
问题2 :即使进行了调整,脚本仍然无法在IE中运行。它在Firefox中工作正常,但在IE 7中我得到了“未知的运行时错误”。
我在JSBIN上有这个代码的示例:
任何人都知道IE正在发生什么事吗?
更新:
我通过谷歌偶然发现了这个链接。请注意最后的评论:
http://msdn.microsoft.com/en-us/library/ms533897%28VS.85%29.aspx
那说,你真的应该把所有 HEAD中的样式规则是严格的 符合XHTML。这样做可以 因为你也有点棘手 不能使用innerHTML注入 直接使用HEAD或STYLE元素。 (这两个标签都是只读的。)
EEP!真正? FireFox是否过于原谅?或者这只是一个非常奇怪的IE怪癖?
更新2:
关于我们在这里要解决的问题的更多背景知识。我们正在处理移动设备和一些过时的设备a)不支持NOSCRIPT和b)缓慢的JS引擎。
由于它们不支持NOSCRIPT,我们默认显示错误,然后通过JS隐藏它(如果有的话),并向它们显示正确的内容。由于这些JS引擎很慢,人们会看到DIV显示/隐藏的“闪烁”。这是处理它的建议解决方案,因为它会在DIV甚至渲染之前加载CSS。
由于它似乎无效,解决方案将是在这些旧设备上,我们将使用此方法(因为它似乎工作,即使不在IE中),然后所有其他适当的浏览器将按照建议执行。 ..我们只需在每个DIV加载到DOM后通过内联JS更新DISPLAY CSS属性。
所有这一切,我仍然很好奇这个问题是IE漏洞,还是IE实际上是通过使STYLE成为只读元素来坚持正确的标准。
答案 0 :(得分:6)
在IE中,您可以使用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);
答案 1 :(得分:1)
不要使用innerHTML
,使用document.createTextNode()
,你的生活会变得无比好;)
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);
编辑:
由于此解决方案似乎不适合您,我会放弃它。而是寻找已定义样式的解决方案,以及通过javascript禁用/启用样式的解决方案。
你可以这样做:
<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>
编辑2:
如果必须在DOM准备好之前完成,你可以做一些像这样丑陋的事情:
<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>
或者为了简单起见,你可以做到
<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>
答案 2 :(得分:0)
最佳做法是将所有&lt; link for CSS放入&lt; head,并将大多数&lt;脚本放在&lt; body的末尾(除了应该执行ASAP的脚本的短片段应该进入) &lt; head)。标准和浏览器都允许你做愚蠢的事情,但仅仅因为它是可接受的并不意味着它是一个好主意。
我建议使用很多更简单的解决方案,而不是经历创建Style节点和操纵DOM(它只是为出错的机会提供更多机会)的所有麻烦。尽可能多地将硬代码放入文档(和样式表?)中(而不是每次都动态创建)。这是一个粗略的例子:
<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 ...
这在大多数情况下应该运行得相当好(它肯定会在比你最初尝试的浏览器更多的浏览器中工作)。 然而,任何尝试在页面最初显示给用户之前以任何方式更改DOM 不保证工作(换句话说,无论你的方式还是上面的例子 总是总是在所有情况下工作)。运行Javascript越早,DOM操作(包括getElementById)就越有可能失败。然后你运行你的Javascript,用户越有可能注意到他们的显示器可察觉的“闪烁”。因此,您可以在广泛的兼容性和明显的闪烁之间进行权衡选择。
您可以等到DOM保证完全就绪,然后再运行Javascript(jQuery中的“ready”,或者addEventListener'domcontextloaded',甚至addEventListener'load')。这保证在所有情况下都能正常工作。 但在许多情况下它会闪烁(也许非常糟糕)。
我知道的唯一方法(但我希望其他人知道更多:-)完全避免闪烁的可能性是将放入&lt; head 一个更改window.location的Javascript片段但没有别的。 (没有对DOM的引用,这通常在代码中的某个地方通过单词“document”显而易见。)如果JS可用,那么净效果将立即重新加载不同的页面,然后向用户显示大部分内容。初始页面可以包含您的警告,新页面可以包含您的警告。
即使这种方法也存在一些缺点:首先,双重下载需要额外的带宽,并且会略微延迟用户的可见性。这在典型的桌面上无关紧要。但在手持设备上它可能是不可接受的。其次,它会加剧对SEO的破坏。第二页 - 应该是不可见的,只能从第一页访问 - 可以在webdexes中独立显示,这样用户就可以轻松地直接访问它(你可以通过巧妙地使用“规范”和/或“修复”它“元......机器人”)。当其唯一的内容是警告信息时,初始页面的SERP可能会急剧下降。