认识 Shadow DOM
Opened this issue · 0 comments
认识Shadow DOM
你知道 Shadow DOM 吗?这个概念你可能不清楚,但我可以确定,你肯定遇见过它们。
Shadow DOM 在哪里
我们来看一个在 Chrome 开发者工具下的截图。
有没有看见一个 #shadow-root
标记?那就是 Shadow DOM 啦。
上图中的 Shadow DOM 是笔者通过 JS 创建的,我们来看一个原生的例子。
一个简单的 <video></video>
元素中原来包含了一个大大的 DOM 树,都在 shadow-root
下,而且在其中还包含了一个子 shadow-root
,真是神奇。video 元素在界面上呈现的UI控制看来都是用 Shadow DOM 方式实现的。
查看方法
怎么查看?你可以打开 Chrome 开发者工具,在设置中勾选上显示 Show user agent shadow DOM
选项,就可以查看页面中是否有 Shadow DOM 了。
Shadow DOM 的创建
一般的 DOM 对象支持一个叫做 createShadowRoot
的方法,这个方法可以给该 DOM 对象创建了一个 shadow root
对象,然后你就可以在这个 root
对象里放你想要的内容了。
var root = document.body.createShadowRoot()
root.innerHTML = '...'
上面的代码中,我们在 body
元素下创建了一个 shadow root
对象。
我们来看看一些相关术语:
shadow host (宿主)
指一个承载了一个或多个节点树的元素(至少有一个是 shadow tree
)。
shadow tree
指一个在 shadow host
中的节点树。
shadow root
指在 shadow tree
中的根元素。
从上图中我们可以看出三者的关系。
Shadow DOM 特性
知道了网页中有 Shadow DOM 的存在,那么它有什么样的特性呢?
游离在外
我们知道 DOM片段
(document fragment),是一棵游离在主 DOM 树之外的节点树,它的创建基于 document
对象。当我们将它作为一个子元素插入到主 DOM 树后,它将变成主 DOM 树的一部分。
Shadow 树也是游离在 DOM 树之外的节点树,但是他的创建基于普通 DOM 元素(非 document
),并且创建后的 Shadow 树节点可以从界面上直观的看到。更重要的是,Shadow DOM 具有良好的密封性。
密封性
在 Shadow 树中,我们只有通过伪元素等进行对内部元素的样式访问,这样可以有效的避免样式冲突。
CSS 渲染 Shadow DOM 的方法:
/*匹配元素下的 shadow tree 中的节点*/
selector::shadow selector {...}
/*匹配祖先元素下的 shadow tree 中的节点*/
selector /deep/ selector {...}
/*匹配 shadow tree 中的 content元素内引用的节点*/
::content > selector {...}
另外还有找到宿主元素的方法,就是使用 :host
,:host-content
伪类。
/*匹配宿主元素*/
:host {...}
/*匹配符合 selector 的宿主元素*/
:host(selector) {...}
/*匹配在 shadow tree 中拥有符合 selector 的元素的宿主元素*/
:host-content(selector) {...}
content 标签
如果你在浏览器下尝试过为一个元素创建一个 Shadow Root,那么你可能会发现,在该元素下创建 Shadow Root 后,该元素中原有的子元素都看不见了。这是由于浏览器不会渲染该元素中的内容,而仅渲染创建的 Shadow Root 中的内容,那么当我们还需要显示一部分原来节点中的内容,该怎么办呢?
虽说界面上看不见了,但是该元素下的子元素都还在,我们可以在 Shadow Root 中使用 content
标签来解决上面的问题。
<div>
<span class="ele">我是子元素</span>
<span class="ele">我是子元素</span>
#shadow-root
<content select=".ele"></content>
</div>
content
标签的 select
属性可以赋值一个选择器,代表你需要放入的元素。上面的例子中我们将两个 span
元素放在了 content
中。
使用 Shadow DOM 的意义
由于以前的组件开放方式是开放式的,即最终生成的 HTML 结构难以与组件外部结构区分,样式容易互相混淆,Shadow DOM 为我们提供了解决这些问题的可能。在 Web 组件化的规范中也可以看到 Shadow DOM 的身影,使用具有良好密封性的 Shadow DOM 开发下一代 Web 组件将会是一种趋势。
浏览器兼容性
Firefox下需要手动开启 Shadow DOM 设置