你需要知道的Shadow DOM

本文作者为 360 奇舞团前端开发工程师

什么是 Shadow DOM

Shadow DOM 简介

在现代的前端开发中,组件化和模块化已经成为构建可维护和可扩展 Web 程序的关键。随着 Web 程序规模的增长,很容易遇到样式和逻辑冲突的问题。为了解决这些问题,Web 标准引入了 Shadow DOM,可以帮助我们更好地隔离和封装组件。提到 Shadow DOM 就不得不提 Web Components。Shadow DOM 是 Web Components 标准的一部分,是 Web Components 中的一个关键技术。它提供了一种将 HTML 结构、样式和行为封装在一个独立的、封闭的 DOM 中的机制。这意味着,使用 Shadow DOM 可以将组件的样式和结构隐藏在组件作用域内,防止其与全局样式或逻辑发生冲突。

Web Components 简介

既然 Shadow DOM 是 Web Components 标准的一部分,那么什么是 Web Components?Web Components 是旨在帮助开发者能够创建可重用的组件,这些组件可以在不同的 Web 应用程序中使用的技术。Web Components 由以下三项主要技术组成:

  • Custom Elements: 一组 JavaScript API,允许开发者定义自己的 HTML 元素和其行为。

  • Shadow DOM: 一组 JavaScript API,提供了一种将 HTML 结构、样式和行为封装在一个独立的、可隔离的作用域内的机制。

  • HTML Templates: 允许开发者定义 HTML 结构的模板,可以作为自定义元素结构的基础被多次重用。

尽管 Shadow DOM 是 Web Components 中的一个关键技术,如果只使用 Shadow DOM 来隔离样式和封装 DOM 结构,也可以单独使用 Shadow DOM,而不定义 Custom Elements 和使用其他 Web Components 技术。比如下面我们先看一下简单的例子。





  
  
  Shadow DOM




  This content is outside Shadow DOM.
  

运行效果如下:你需要知道的Shadow DOM_第1张图片

Shadow DOM 核心概念

Shadow DOM 允许将隐藏的 DOM 树附加到常规的 DOM 树中——它以 shadow root 节点为起始根节点,在这个根节点的下方,可以是任意元素,和普通的 DOM 元素一样。

你需要知道的Shadow DOM_第2张图片 image.png
  • Shadow host:一个常规 DOM 节点,作为 Shadow DOM 的容器。Shadow DOM 会被附加到这个节点上。Shadow host 将 Shadow DOM 插入到文档中,作为 Shadow DOM 的入口点。它是外部 DOM 和 Shadow DOM 之间的连接点。

  • Shadow tree:Shadow DOM 内部的 DOM 结构。包含完整的的 HTML 结构、样式和行为,形成一个独立的渲染上下文。

  • Shadow boundary:Shadow DOM 结束的地方,也是常规 DOM 开始的地方。确保样式和 DOM 结构的隔离。

  • Shadow root: Shadow tree 的根节点。包含 Shadow DOM 的所有内容,它是 Shadow DOM 内部结构的入口。通过创建 Shadow Root,可以将 Shadow DOM 附加到 Shadow host 上。

Shadow DOM 都不是一个新事物——在过去的很长一段时间里,浏览器用它来封装一些元素的内部结构。以一个有着默认播放控制按钮的 元素为例。你所能看到的只是一个 标签,实际上,在它的 Shadow DOM 中,包含了一系列的按钮和其他控制器。Shadow DOM 标准允许你为你自己的元素(custom element)维护一组 Shadow DOM。

我们可以 Dev Tools 中通过 Network -> Add -> Preferences -> Show user agent shadow DOM 来查看 video 的内部信息(操作步骤如下)。

你需要知道的Shadow DOM_第3张图片 你需要知道的Shadow DOM_第4张图片 你需要知道的Shadow DOM_第5张图片

Shadow DOM 使用

基本用法

要在项目中使用Shadow DOM,需要以下步骤:

  • 获取/创建 Shadow host 作为 Shadow DOM 的容器。

  • 创建 Shadow DOM :使用元素的 attachShadow 方法来创建 Shadow DOM。这个方法接受一个参数,即一个包含 mode 属性的配置对象,该属性可以是 'open' 或 'closed'。'open' 表示可以通过 JavaScript 访问 Shadow DOM,而 'closed' 则表示无法通过 JavaScript 直接访问。

  • 定义 Shadow DOM 的内容:在创建的 Shadow DOM 中,你可以添加自己的 HTML 结构和样式。

在开始之前先看下面的代码:





  
  
  Shadow DOM Example
  



  
  
   你需要知道的Shadow DOM_第6张图片

在上面的代码中,我们创建了一个普通按钮和一个使用Shadow DOM的按钮。Shadow DOM中的按钮样式独立于页面上的全局样式,因此它具有不同的背景颜色(红色)。Shadow DOM的一个重要特性是它提供了封装性,使得内部的样式和结构不会影响到外部的文档。

Shadow DOM Mode

同时我们可以注意到 { mode: 'open' } 传的是 open,mode 的取值为 open 和 closed





  
  
  Shadow DOM Example




  
    

paragraph

  
  
   你需要知道的Shadow DOM_第7张图片




  
  
  Shadow DOM Example




  
    

paragraph

  
  
   你需要知道的Shadow DOM_第8张图片

通过上面的例子可以看到,open模式允许外部访问Shadow DOM,而closed模式则不允许。

Shadow DOM 优势

  • 封装:Shadow DOM允许开发者将组件的HTML、样式和行为封装在一起,使其成为一个独立的单元。这有助于降低组件之间的耦合度。

  • 隔离:Shadow DOM内部的DOM结构对外部不可见,从而避免了全局作用域的样式和脚本冲突。这有助于提高代码的可靠性。

Shadow DOM 劣势

  • 学习曲线:使用和理解 Shadow DOM 需要一定的学习曲线,特别是对于那些不熟悉 Web 组件概念的开发者。

  • 调试困难:由于 Shadow DOM 的封装性质,调试组件内部的 DOM 结构和样式可能变得更加困难。

  • 浏览器支持:虽然大多数现代浏览器都支持 Shadow DOM,但在某些特定环境或设备上,可能会遇到兼容性问题。

Shadow DOM 和 Iframe

Shadow DOM 更适合于构建具有封装性和局部样式的组件,而