探索 CSS Shadow DOM 与 CSS Custom Shadow Parts
Source: Dev.to
现代网页开发强调构建可复用、封装的组件——这正是 Shadow DOM 和 CSS Custom Shadow Parts 直接解决的目标。这些浏览器特性将组件内部与全局页面隔离,避免样式泄漏和冲突,同时仍然允许受控的自定义。
什么是 Shadow DOM?
Shadow DOM 是一种网页标准,允许你为元素创建一个独立、封装的 DOM 子树,称为 shadow tree。子树的标记和样式与主文档 DOM 隔离,防止意外干扰。它是 Web Components 背后的基础技术。
封装
内部结构和样式对主文档及外部 CSS 隐藏。
作用域样式
shadow tree 内的样式只影响其节点;页面样式不会渗透进去。
Shadow Host
承载 shadow tree 的普通 DOM 元素。
Shadow Root
shadow tree 的根节点,通过 JavaScript 使用 attachShadow() 创建。
const host = document.querySelector('#host');
const shadow = host.attachShadow({ mode: 'open' });
const span = document.createElement('span');
span.textContent = "I'm inside the shadow DOM!";
shadow.appendChild(span);
如果没有 Shadow DOM,外部页面样式可能意外覆盖组件内部样式(反之亦然),使大型应用更难维护。Shadow DOM 为组件创建一个“样式和标记的气泡”,确保无论周围页面如何,都能得到可预测的行为。
Shadow DOM 内的样式
由于样式被限制在 shadow root 内部,你可以在 shadow 树中使用普通 CSS 对 shadow‑DOM 元素进行内部样式设置。
shadow.innerHTML = `
span {
color: red;
border: 1px solid black;
}
Shadow DOM content
`;
此 CSS 仅作用于 shadow 树内部的元素,防止与外部样式产生冲突。
CSS 自定义 Shadow 部分
虽然 Shadow DOM 提供了封装,但它也限制了从外部自定义内部元素。CSS 自定义 Shadow 部分让 Web 组件能够暴露特定的内部元素,以便在不破坏封装的前提下进行外部样式化。
/* External stylesheet */
my-component::part(button) {
background-color: green;
border-radius: 5px;
}
示例组件
class MyButton extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' }).innerHTML = `
button {
background-color: blue;
color: white;
padding: 10px;
border: none;
cursor: pointer;
}
Press me
`;
}
}
customElements.define('my-button', MyButton);
外部样式
my-button::part(button) {
background-color: orange; /* Override internal button style */
}
外部 CSS 作用于内部按钮的 part="button",而组件的其余部分仍保持封装。
关键特性
| 功能 | 描述 |
|---|---|
| Shadow DOM | 将标记和样式封装在 shadow root 中,使其与页面样式隔离。 |
| Shadow Host | 承载 shadow root 的普通 DOM 元素。 |
| Scoped Styles | shadow root 内的样式仅在该树内部生效。 |
| CSS Custom Shadow Parts | 为外部样式化内部组件部件提供官方方式。 |
part attribute | 标记内部元素,以便对外部进行样式暴露。 |
::part() selector | 从 shadow root 外部定位部件进行自定义样式。 |
结论
通过使用 Shadow DOM 和 CSS Custom Shadow Parts,开发者可以创建健壮、可维护的 Web 组件,这些组件既是封装的又可定制的——开启了可重用 UI 构建块的新时代。