3

我有一个两部分的问题。

一、场景:

由于我们在移动浏览器对 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);

但是,我遇到了问题。如果您尝试将 innerHTML 插入到创建的元素中,然后再将其放入 DOM 中,则一些谷歌搜索会导致 IE 可能遇到的安全问题的描述:

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 上有这段代码的示例:

http://jsbin.com/ucesi4/4

有谁知道IE是怎么回事?

更新:

我通过谷歌偶然发现了这个链接。注意最后一条评论:

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

也就是说,您确实应该将所有样式规则放在 HEAD 中,以严格遵守 XHTML。这样做也可能有点棘手,因为您不能使用 innerHTML 直接注入 HEAD 或 STYLE 元素。(这两个标签都是只读的。)

哎呀!真的?火狐只是过于宽容了吗?或者这只是一个非常奇怪的 IE 怪癖?

更新 2:

关于我们在这里尝试解决的问题的更多背景信息。我们正在处理移动设备和一些过时的设备 a) 不支持 NOSCRIPT 和 b) 具有慢速 JS 引擎。

由于他们不支持 NOSCRIPT,我们默认显示一个错误,然后通过 JS 隐藏它(如果有),并为他们提供正确的内容。由于这些 JS 引擎的速度很慢,人们会看到 DIV 显示/隐藏的“闪烁”。这是处理该问题的建议解决方案,因为它会在 DIV 甚至渲染之前加载 CSS。

由于它似乎无效,解决方案将是在这些旧设备上,我们将使用此方法(因为它似乎有效,即使不在 IE 中),然后所有其他合适的浏览器将按照建议进行......我们'将在每个 DIV 加载到 DOM 后通过内联 JS 更新 DISPLAY CSS 属性。

尽管如此,我仍然很好奇这个问题是否是一个 IE 错误,或者 IE 是否通过使 STYLE 成为只读元素实际上遵守了正确的标准。

4

3 回答 3

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);

在这里试试这个:http: //jsfiddle.net/QqF77/

请参阅此问题的答案:如何使用 Javascript 创建 <style> 标记

于 2011-09-04T11:43:29.813 回答
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>
于 2011-03-08T08:20:00.367 回答
0

最佳实践是将 CSS 的所有 <link 放入 <head,并且将大多数 <script 放在 <body 的最末端(除了应该尽快执行的 <script 的短片段应该放在 <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 中的“准备就绪”,或者 addEventListener 'domcontextloaded',甚至 addEventListener 'load')。这保证在所有情况下都能正常工作。在许多情况下它会闪烁(可能非常严重)。

我知道的唯一方法(但我希望其他人知道更多:-) 完全避免闪烁的可能性是在 <head中放入一个 Javascript 片段,该片段会更改 window.location 但不执行任何其他操作。(没有对 DOM 的引用,这通常通过代码中的“文档”一词显而易见。)如果 JS 可用,最终效果将是在向用户显示大部分内容之前立即重新加载不同的页面。初始页面可以包含您的警告,新页面可以包含没有警告的真实内容。

即使这种方法也有一些缺点:首先,双重下载需要额外的带宽并稍微延迟用户可见性。这在典型的台式机上无关紧要。但在手持设备上可能无法接受。其次,它将对搜索引擎优化造成严重破坏。第二页 - 应该是不可见的,只能从第一页访问 - 可能会在 webdex 中独立显示,因此用户可以轻松地直接访问它(您可以通过巧妙地使用“规范”和/或“元......机器人”)。而当其唯一的内容是警告信息时,初始页面的 SERP 可能会急剧下降。

于 2013-06-12T16:26:02.017 回答