如果您在 Google 上搜索此问题(在撰写本文时),您会发现一些不完整的答案,以及一些提倡这种不良实践的其他代码片段。
<!-- NO! Bad! -->
<iframe src="..." style="visibility:hidden;" onload="this.style.visibility='visible';"></iframe>
之所以不好,是因为 CSS 会始终隐藏 iframe,而禁用 JavaScript 的用户将永远无法看到该 iframe。现在,我通常不会为了迎合这部分人群而费尽心思,但我完全赞成使用更好的解决方案来解决此问题(如果可用)。
解决方案
感谢 Paul Irish 及其 可靠的 DOM 元素插入,以及 Ryan Seddon 及其关于 插入作用域样式元素的文章,我们有了这个方法。
// Prevent variables from being global
(function () {
/*
1. Inject CSS which makes iframe invisible
*/
var div = document.createElement('div'),
ref = document.getElementsByTagName('base')[0] ||
document.getElementsByTagName('script')[0];
div.innerHTML = '­<style> iframe { visibility: hidden; } </style>';
ref.parentNode.insertBefore(div, ref);
/*
2. When window loads, remove that CSS,
making iframe visible again
*/
window.onload = function() {
div.parentNode.removeChild(div);
}
})();
只需在出现白屏闪烁问题的任何页面(在 <head>
中)包含此代码,问题即可解决。请注意,我们在这里使用的是 window.onload,因此如果您的页面也在其他地方使用了它,请将它们合并。
工作原理
- 它在页面上插入了一些 CSS(立即生效),使所有 iframe 都不可见。您无法在不存在的 iframe 上看到白屏闪烁!
- 窗口加载完成后(这意味着 iframe 也加载完成),此 CSS 将被移除,使 iframe 再次可见。
受影响的浏览器
在撰写本文时,我能够在 Chrome 11 和 Safari 5 中重现此问题(基本上是 WebKit 问题)。当前版本的 Firefox、Opera 和 IE 则没有此问题。
其他方法怎么样?
您可以在 iframe 上添加 allowtransparency="true"
属性。您可以使用 CSS 将 iframe 的背景设置为透明。您可以确保源文档的背景与父页面的背景匹配。这些方法都不起作用。此方法有效。好吧……它对启用了 JavaScript 的用户有效。=)
“­” 是什么意思?
查看 Ryan Seddon 的文章:http://www.thecssninja.com/javascript/noscope
这篇文章主要讲的是 IE 在插入时会删除 style 标签,防止这种情况发生,并使用一个对渲染没有影响的字符来实现。
(那是“shy”字符……无论这意味着什么)
为什么不使用一个带有普通 iframe 的
<noscript>
标签,然后使用 JavaScript 为其他所有人添加 iframe 呢?我的 HTML 代码被清理了,它应该写成
为什么不使用一个带有普通 iframe 的 “noscript” 标签,然后使用 JavaScript 为其他所有人添加 iframe 呢?
我不确定这是否有帮助。当 JS 插入 iframe 时,它仍然会加载并仍然会出现白屏闪烁。除了您可能可以执行相同的隐藏可见性技巧,直到它加载为止。似乎有点不可扩展,必须将要插入的每个 iframe 的标记都放入 JavaScript 中,有点像混合了内容和行为。
您仍然需要使用 JavaScript,所以我认为此解决方案更容易,并且应该无需编辑页面即可工作,只需“粘贴并运行”即可。
你好!
精彩的文章!
不过有一点:我相信您的意思是“您无法在不存在的 iframe 上看到白屏闪烁!”
不错的文章,但总的来说,iframe 技术太旧了。您最好明确使用其他方法,例如通过 PHP 动态生成内容。
iframe 还会存在一段时间。我认为它是一个非常好的东西。YouTube 视频是 iframe 嵌入。Wufoo 表单是 iframe 嵌入。它们对于托管第三方内容非常有用,在这些内容中,您需要/希望这两件事的控制权是分开的。
YouTube、Facebook 等流行的网络服务提供的 iframe 支持并不意味着 iframe 是处理外部内容的好方法。有一些现代解决方案,例如 SOAP 或 CURL,可以处理此问题。(抱歉我的英语不好,我来自德国)
我不得不赞同 Chris 的观点。我为一家大型公司工作,我们有一款新的、大型的 SaaS 产品,它完全依赖于 iframe。
所以您认为 YouTube 视频应该将其复制粘贴的可嵌入视频代码作为带有 CURL 调用的 PHP 提供吗?
iframe 是容纳外部内容的完美方式,正如 Chris 所说,越来越多的大型公司使用它们来嵌入其内容(YouTube、Vimeo、Facebook、Twitter……),因此它们将在很长一段时间内存在。
>> 所以您认为 YouTube 视频应该将其复制粘贴的可嵌入视频代码作为带有 CURL 调用的 PHP 提供吗?
是的,为什么不呢。也可以共享 JSON/XML/任何接口,这些接口可以通过 JavaScript 轻松调用。
我认为 iframe 使用起来非常简单,即使对于那些不熟悉设计领域或不习惯查看代码的人来说也是如此。对于很大一部分人来说,仅仅复制粘贴就已经足够困难了。这可能是 YouTube 切换到 iframe 嵌入的原因,因为它看起来不那么复杂了。
我看到此代码后就立即在我的网站上实现了这个白屏闪烁预防代码。
感谢 Chris,并为您的出色工作点赞。
如果 iframe 是使用 JavaScript 插入的,此方法是否也有效?
例如
谢谢,非常有用。我将在我的网站上使用它。
这实际上是防止皮肤下拉菜单和自定义滚动条等内容出现意外样式闪烁的好方法。很高兴看到这种方法越来越流行,并被用于 iframe!
“请注意,我们在这里使用的是 window.onload,因此如果您的页面也在其他地方使用了它,请将它们合并。”
为什么?我以为当您为某个事件注册多个函数时,它们会依次堆叠并运行。是这样吗?
顺便说一句,您知道可以通过脚本获取 iframe 的内容吗?您只需要这个
getElementById('myiFrame').contentWindow
,它将返回该 iframe 的“窗口”对象,现在您可以执行以下操作这是一个有两个 window.onload 声明的示例:http://jsfiddle.net/chriscoyier/gb7gt/——您只会得到第二个声明。可能还有更好的方法来处理这个问题。我对 JavaScript 还不太熟悉。
对于关于访问 iframe 内部内容的第二部分,我敢肯定,这仅适用于相同域的 iframe。
Chris 说得对,‘window.onload’ 只能附加到一个函数调用上。使用它两次意味着只有第二个调用会被触发。要实现 Hassan 所建议的,你可以使用一个 ‘init’ 类型的函数在 ‘window.onload’ 时运行,然后进行多次函数调用来获得你描述的堆叠行为。
是的,完全正确,这就是为什么我在文章中说要注意这一点并把它们结合起来。就像你说的,这是理想的方式,创建一个 init 函数并调用它,其中包含任何你想在 window.onload 时运行的内容。
“正确”的方法是对于 IE 使用 “attachEvent”,对于其他所有浏览器使用 “addEventListener”。这样你就可以将任意数量的回调函数附加到一个事件上。
我通过简单地为 iframe 元素使用 CSS 背景颜色,成功地去除了一个网站上的 iframe 白屏闪动。这对于图像背景不适用,但在某些情况下是一个可行的选项。
感谢您撰写如此精彩且有价值的文章!
这在我处理 Flash 时肯定会有帮助。
ref = document.getElementsByTagName(‘base’)[0] ||
document.getElementsByTagName(‘script’)[0];
太棒了!!!
在 HTML 或 body 标签上应用一个类,然后在页面加载时移除它怎么样?我使用类似的技术(不移除类)来处理依赖于 JS 的样式。
头部中的 JavaScript
样式表中的 CSS
也喜欢。
尽管全 JS 解决方案更容易复制粘贴完成,并且在某些情况下,比如 Wufoo 表单嵌入(最初我之所以要处理这个问题的原因),它是唯一的选择。
如果在一个页面中使用 iframe,并且每次点击菜单项都会在同一个 iframe 中加载不同的内容,该怎么办?页面不会重新加载,只有 iframe 内容会重新加载。如何修改你的脚本来防止这种白屏闪动?
谢谢,我找了一个小时的解决方案!当 iframe 中是支付网关时,它看起来不太好,客户很容易失去信心。
我在使用 fancybox (www.fancybox.net) 时遇到了这个问题。fancybox 使用 iframe,所以它在一定程度上起作用了。唯一的问题是,一旦页面加载到 fancybox 中,CSS 不会被移除,内容仍然隐藏。
有没有人足够熟悉 fancybox 来帮我解决这个问题?我对 javascript 也不熟悉,我确定这是一个简单的调整就可以解决,但我不知道从哪里开始。
如何将此代码添加到我的页面?我需要在 标签内插入吗?还是 标签内?
我试图在一个 Hype (http://www.tumultco.com/hype/) 网站的场景中嵌入的 iframe 中使用它。包含 iframe 的页面作为场景访问,因此页面不会完全“加载”。
iframe 链接是在内部 HTML 窗口中添加的。
我可以在其他地方添加此代码吗?
如果没有,上面哪个答案最适合,也许是在 iframe 代码内部或旁边添加自定义 CSS?
谢谢!
嗨,Chris。感谢你的帮助。我按照你的说明将代码粘贴到了头部。闪动消失了,但视频也消失了。只能听到音频。这是为什么?
此致,