大约一年前,Twitter 宣布 它将开始使用 Shadow DOM 而不是 <iframe>
来显示嵌入的推文,如果浏览器支持 Shadow DOM。
为什么?好吧,速度是一个原因。
他们说
浏览器中的内存使用率大大降低,渲染速度也快得多。推文将更快地出现,页面滚动将更加流畅,即使在同一页面上显示多个推文也是如此。
为什么选择?为什么必须使用 iframe 或 Shadow DOM?为什么不直接将内容注入页面?


对于控制来说,这是一个完全可以理解的需求。嵌入的推文应该看起来和行为就像嵌入的推文一样。他们不想担心页面样式的渗入,从而破坏了这一点。
<iframe>
使样式范围变得非常容易。将 iframe 的 src
指向一个 URL,该 URL 显示您希望嵌入的推文看起来像什么,这样就可以了。唯一使用的样式将是您在该文档中包含的样式。
Twitter 以一种渐进增强和便于聚合的方式执行此 iframe 注入。他们提供了一个带有推文的 <blockquote>
和一个 <script>
。脚本执行 iframe 注入。如果脚本没有运行,没关系,一个快乐的块引用。如果脚本运行,则是一个功能齐全的嵌入式推文。
该脚本是这里的关键。脚本几乎可以做任何事情,并且他们托管它,因此他们可以随时更改它。这就是他们用来检测 Shadow DOM 支持并改用该方式的方法。正如我们所述,Shadow DOM 渲染速度更快,内存需求更低。Shadow DOM 还可以帮助解决样式范围问题,我们将在稍后讨论。
高度灵活性
还有另一件事,它恰好是我最喜欢的。<iframe>
不会像您期望其他元素那样调整高度以适应其内容。您设置一个高度,就是这样。如果允许它并且内容需要它,它将有滚动条。在 Wufoo 时代,我们不得不跳过很多圈子才能使嵌入的表单(在框架中)达到它们需要的高度。如今,在 CodePen,我们的嵌入式 Pen 具有可调整的高度,但没有“与它们需要的高度一样高”的选项。(我不确定这对 CodePen 嵌入是否说得通,但无论如何,您现在无法做到这一点。)
具有 Shadow DOM 的元素就像任何其他元素一样,它会自然地扩展到内容。我相信这对 Twitter 也很有吸引力。如果他们计算的高度错误,他们就有可能截断内容,或者至少使嵌入的推文看起来很糟糕。
最基本用法
以下是建立 Shadow DOM 和在其中放置内容的最低限度
查看 CodePen 上 Chris Coyier 的 最基本的 Shadow DOM (@chriscoyier)。
注意 Shadow DOM 中的样式如何不泄漏到常规段落元素?如果这样做,两个段落都会是红色的。
还要注意 Shadow DOM 内部的段落不像外部的段落那样是 sans-serif 吗?嗯,通常是这样的。继承的样式仍然会通过 Shadow DOM 继承(因此,从某种意义上说,它不像 iframe 那样是一个强大的屏障)。但是,我们像这样有意地将其强制回到初始状态
:host {
all: initial;
}
处理回退
我最初的想法是,对于不支持 Shadow DOM 的浏览器,您可以将与您塞入 Shadow DOM 中的完全相同的内容放入具有 srcdoc
的 iframe 中,就像这样...
<iframe srcdoc="the same content">
或者更可能是您在 JavaScript 中进行此操作,因此您将首先测试支持,然后执行 Shadow DOM 内容或动态创建 iframe
查看 CodePen 上 Chris Coyier 的 Shadow DOM 基本 (@chriscoyier)。
事实证明,srcdoc
(单独使用)不是回退的最佳选择,因为它在 IE 或 Edge 中不受支持。但使用数据 URL 进行常规 src
也不是什么大问题。以下是 Šime Vidas 修复了这个问题的分支
let content = `
<style>
body { /* for fallback iframe */
margin: 0;
}
p {
border: 1px solid #ccc;
padding: 1rem;
color: red;
font-family: sans-serif;
}
</style>
<p>Element with Shadow DOM</p>
`;
let el = document.querySelector('.my-element');
if (document.body.attachShadow) {
let shadow = el.attachShadow({ mode: 'open' }); // Allows JS access inside
shadow.innerHTML = content;
} else {
let newiframe = document.createElement('iframe');
'srcdoc' in newiframe ?
newiframe.srcdoc = content :
newiframe.src = 'data:text/html;charset=UTF-8,' + content;
let parent = el.parentNode;
parent.replaceChild(newiframe, el);
}
TL;DR
- Shadow DOM 很酷。
- 它在许多方面与 iframe 相似,包括样式封装。嵌入的第三方内容是一个很好的用例。
- 可以在回退到 iframe 时使用它,这非常容易。
- 它是 Web Components 更大世界的一部分,但如果您不想这样做,您不必完全投入其中。
以下是一些 简单的演示(这个演示使用自定义元素),但它不是自己回退,而是使用 polyfill。
<iframe>
不会保证一些<script>
标签无法提供的安全沙箱吗?第三方<script>
标签可以更改页面上任何地方的任何内容,或者静默读取页面上的任何内容,这对安全性来说不是很好。至少使用<iframe>
,您知道它只能访问和修改其内部的内容。我喜欢 Shadow DOM 的感觉,它与 flexbox 曾经的感觉很相似。迫不及待地想看到项目使用 Shadow DOM
这就是文章中所有关于回退的内容。如果您对 iframe 回退感到满意,那就去做吧。
我们已经使用 Shadow Dom 好几年了。
iframe 回退在 IE 中对我来说失败了。IE 中似乎只允许对数据 URI 进行有限的操作。还有其他解决方法吗?真的很喜欢这种封装,但像往常一样,IE 毁掉了派对。
我发誓我曾在 IE 中检查过。现在我检查时出现了一堆安全错误。好吧,至少它在 Firefox 和 Edge 中运行,这很有希望。
相关