AI PLAY玩法更新持续收录
← 回到更新流

2026-09-23 · 原文发布日

用交互实例讲透 Shadow DOM

Simon Willison 用 AI 工具生成交互式页面来讲解 Shadow DOM:通过可点击的实例演示样式隔离、继承、slots、parts 和 JavaScript 访问等概念,展示 shadow root 如何创建带私有样式表的独立 DOM 树。适合前端开发者或学习者直观理解这一机制,也可参考其“用一句话让 AI 生成教学 artifact”的做法。

原文要点

Simon Willison发布了一个讲解Shadow DOM的交互式页面,演示样式封装、继承、slots、parts与JavaScript访问,展示shadow root如何创建带私有样式表的隔离DOM树。该页面是他用一句话提示词让Fable 5.1 Medium生成的artifact:‘Build an artifact to explain shadow roots in CSS with interactive examples’。原文本身只含工具链接与这条提示词,没有展开技术内容。

这次做成什么

照作者的方法自己造一个可交互的Shadow DOM教学单页:用一句提示词让AI生成初版,再用本站给出的完整HTML校验并补足五个必讲概念,最后本地打开逐项点击验证。

准备什么

  • 任意现代浏览器(Chrome/Edge/Firefox/Safari均可)
  • 一个可生成HTML artifact的AI工具(如Claude/Fable类)
  • 本地保存与打开单个HTML文件的权限,无需构建工具

具体怎么做

  1. 用一句话生成初版

    在AI工具中输入作者同款提示词“Build an artifact to explain shadow roots in CSS with interactive examples”,让它输出一个单文件HTML页面。

  2. 对照五概念清单补齐

    检查生成页是否覆盖:样式封装、继承、slots、parts、JavaScript访问。缺哪项,就把本站artifact中对应小节代码并入,或追问AI按该小节补齐。

  3. 本地运行并逐项点击

    把最终HTML存为shadow-dom-demo.html双击打开,依次操作:修改宿主页全局样式看shadow内部是否不受影响、向slot传入不同内容、用part选择器从外部改样式、点击按钮触发通过shadowRoot引用执行querySelector('.inner')的访问,并观察控制台输出。

  4. 验证隔离边界

    在页面里把宿主div的文字颜色改成红色,确认无shadow的普通段落变红而shadow内部段落颜色不变;再用浏览器DevTools查看shadow root在DOM树中的独立挂载点。

可直接复制的材料

shadow-dom-demo.html(可直接保存运行的教学页)

本站独立编写的完整示例,非原作者页面;覆盖样式封装、slot、part、JS访问四个交互点,继承概念在页面正文中由对比段落体现,可直接保存运行。

<!DOCTYPE html>
<html lang="zh">
<head><meta charset="utf-8"><title>Shadow DOM 交互演示</title>
<style>body{font-family:sans-serif} p{color:gray} .plain{color:green}</style>
</head>
<body>
<h1>Shadow DOM 五个概念</h1>
<p class="plain">这是普通段落,受页面全局样式控制(绿色)。</p>
<div id="host"></div>
<button id="jsBtn">3) 用JS读取shadow内部文本</button>
<button id="partBtn">4) 通过part从外部改按钮颜色</button>
<pre id="log"></pre>
<template id="tpl">
  <style>
    p{color:rebeccapurple} /* 私有样式:不受外部 p{color:gray} 影响 */
    .btn{padding:4px 8px}
    ::slotted(span){font-weight:bold}
  </style>
  <p class="inner">1) 样式封装:我在shadow里,始终是紫色。</p>
  <p>2) slot插槽:<slot name="msg">默认内容</slot></p>
  <button class="btn" part="btn">part暴露的按钮</button>
</template>
<script>
const host=document.getElementById('host');
const root=host.attachShadow({mode:'open'});
root.appendChild(document.getElementById('tpl').content.cloneNode(true));
host.innerHTML='<span slot="msg">传入的slot内容</span>'+host.innerHTML;
document.getElementById('jsBtn').onclick=()=>{
  document.getElementById('log').textContent='JS访问结果: '+root.querySelector('.inner').textContent;
};
document.getElementById('partBtn').onclick=()=>{
  const st=document.createElement('style');
  st.textContent='#host::part(btn){background:tomato;color:#fff}';
  document.head.appendChild(st);
};
</script>
</body></html>

输入与输出示例

本站虚构演示预期效果,未声称实际运行;不同浏览器渲染细节一致但默认字体可能略有差异。

输入

把上方HTML保存为shadow-dom-demo.html并在浏览器打开,点击“用JS读取shadow内部文本”按钮

对应输出

页面表现:普通段落显示绿色;shadow内段落显示紫色(不受全局p{color:gray}影响);slot位置显示加粗的“传入的slot内容”;点击按钮后pre区域输出“JS访问结果: 1) 样式封装:我在shadow里,始终是紫色。”;再点part按钮后shadow内按钮变为番茄红底白字。

做完检查这些

  • shadow内部段落颜色为紫色且不随页面全局p样式变化
  • 向slot传入的span内容替换默认内容且被加粗
  • 点击JS按钮后日志区出现shadow内部文本,证明attachShadow(mode:open)可被外部访问
  • part按钮生效,证明::part()可从外部穿透样式封装
  • DevTools中能看到#host下的#shadow-root独立节点

容易卡住的地方

  • attachShadow用mode:closed时外部querySelector拿不到内部节点,教学页需用open
  • ::part()只能选中显式声明part属性的元素,不能任意穿透
  • 全局CSS自定义属性(变量)会继承进shadow,颜色字面量则不会
  • 原文只是工具链接加一句提示词,技术细节为本站补齐,勿当成原作者内容
  • 部分AI生成页会漏掉parts或JS访问,需按清单逐项验收

原文与作者资料 ↗

本站借助AI整理来源事实,独立编写中文操作指南与示例。示例不代表实际运行结果;来源效果尚未由本站独立复现。付费模板与模型、服务费用分别计算。

原文标题
Shadow roots, explained with live examples
原作者
Simon Willison
原始发布日期
2026-09-23
来源
https://simonwillison.net/2026/Sep/23/shadow-roots/