配了八年Web Components,今天发现它的SSR从来就没真正立住过——Declarative Shadow DOM升入Baseline让这件事彻底变了

写了八年 Web Components,今天发现它的根子一直没立对——因为 Shadow DOM 只能靠 JS 挂上去,内容在浏览器拿到之前根本不存在。2026 年 8 月,Declarative Shadow DOM 正式升入 Baseline「广泛可用」,这件事才真正立住了。

## 八年了,Web Components 的问题一直没变

Web Components 三件套:Custom Elements、Shadow DOM、HTML Templates。Custom Elements 是纯 HTML,Slots 是纯 HTML,唯独 Shadow DOM 这件事,必须靠 JavaScript。

传统做法:

“`javascript
class UserCard extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: ‘open’ });
this.shadowRoot.innerHTML = `.card { … }…`;
}
}
customElements.define(‘user-card’, UserCard);
“`

这段代码在 “ 加载之前,`user-card` 就是一个空标签。搜索引擎看不到内容,CSS 看不到结构,FCP 之前用户看到的是空白。这是 Shadow DOM 自 2019 年 V1 定稿以来的「胎里带」问题。

## Declarative Shadow DOM 把这件事翻过来了

2026 年 8 月,Declarative Shadow DOM(DSD)正式升入 Baseline「广泛可用」—— Chrome/Edge 111(2023 年 3 月)、Safari 16.4(2023 年 3 月)、Firefox 123(2024 年 2 月),三引擎全部支持超过 30 个月,跨浏览器兼容性的最后一道门槛没了。

核心区别就一个:shadow root 可以直接写在 HTML 里,不需要 JS:

“`html

.card { border: 1px solid #dee2e6; padding: 1rem; border-radius: 8px; }

Jane

Jane Smith

Lead Engineer

“`

浏览器在解析 HTML 时,遇到 “ 就自动把它的内容变成 shadow root——没有任何 JS 参与。Shadow root 在首屏 HTML 到达时就已经存在,内容可见、样式就位、SEO 可索引。

## 数字不是最大的变化,可感知的体验才是

这不是「快几毫秒」的性能优化,是整个 SSR 范式的换挡。

**无 FOUC 首屏。** 以前 Web Components 的标准 UX 是:用户先看到未样式化的空标签,JS 加载后才出现完整组件。DSD 消除了这个间隙——shadow root 和内容随 HTML 一起到达,第一帧就是最终效果。

**流式渲染天然适配。** DSD 在 HTML 解析阶段工作,配合 HTTP Streaming,可以在慢数据到达之前先发送组件骨架。用户不会盯着 loading 态干等,内容是渐进式呈现的。

**SEO 不再是问题。** Google 的 crawler 可以索引 shadow DOM 内容,但其他搜索引擎(Bing、DuckDuckGo)在很长一段时间内只索引 HTML 原文,不执行 JS。DSD 让所有搜索引擎在 HTML 阶段就能看到组件内容,索引覆盖率直接拉平。

**JS 移出关键渲染路径。** 组件的交互逻辑可以继续用 JS,但首屏渲染不再依赖 JS 加载。组件在 JS 到达之前就已经以完整结构呈现,JS 到达时「pick up」已有 shadow root 做增强——这个过程叫「instant hydration」,React Server Components 追求的同一个目标,Web Components 现在原生支持了。

## 实际例子:一个 UserCard 的两种写法对比

**旧写法(JS 挂载,必须等 JS 加载):**

“`html


“`

**新写法(DSD,服务端直出):**

“`html

.card { border: 1px solid #e5e7eb; padding: 1rem; border-radius: 0.75rem; }
h2 { margin: 0; color: #111; }
img { border-radius: 50%; width: 48px; height: 48px; }

avatar

Jane Smith
Lead Engineer

“`

差别不只是代码量——第二种写法的内容在 HTML 响应到达时就已经完整存在,不管用户网络多慢,不管 JS 加载顺序是什么。

## 适用场景:什么时候 DSD 真正有价值

**值得用:**
– 内容密集型站点(编辑平台、电商列表、媒体站点),SSR 是主要渲染策略
– 设计系统组件,封装样式但不依赖框架
– 需要 SEO 的自定义组件(产品卡片、作者卡片、数据面板)
– 流式渲染场景,慢数据分批到达

**不太值得用:**
– 强交互组件(拖拽、复杂状态机),JS 负载本来就是必要的
– 纯 SPA 项目,客户端渲染本来就不依赖 HTML 里的内容
– 已有成熟的 SSR 方案且工作正常,不值得为了这个迁移

## 有一个坑, demos 里不常提

DSD 的 shadow root 解析只在 HTML 解析阶段发生。这意味着:**用客户端路由(无刷新导航)时,DSD 只在第一次完整页面加载时生效**。之后的页面切换不会重新解析 HTML,shadow root 就不会重新挂载。

Mintec 在一个使用 `@astrojs/lit` + View Transitions 的真实项目里踩到这个坑:初始加载完美,客户端导航之后组件就变成了空标签。这个问题没有完美的通用解法,需要在框架层处理——要么强制刷新导航到带 DSD 的完整页面,要么在路由切换时手动触发组件升级。

这不是 DSD 的 bug,是 SSR-first 架构在 SPA 时代的固有矛盾。知道这个边界,就知道什么时候该用它、什么时候该绕开。

## 迁移路径

已有组件迁移到 DSD 思路很清晰:

1. 把 `attachShadow()` 的 HTML 模板改成 “ 放在组件标签内部
2. 服务端直接输出带 shadow root 的 HTML(任何 SSR 框架都支持,模板语言直出即可)
3. 客户端的 JS 只负责增强已有 shadow root,不需要重新创建

对于 Astro、Next.js、Nuxt 这类 SSR-first 框架,这个迁移几乎是纯前端改动,不需要改后端逻辑。

2026 年 8 月 DSD 升入 Baseline「广泛可用」,是 Web Components 诞生以来最重要的一个里程碑。八年了,它终于可以在服务端渲染、可以被搜索引擎索引、可以在 JS 加载之前就完整呈现——不靠任何 polyfill,不靠框架特殊处理,就靠浏览器原生支持。如果你的项目里还有靠 JS 挂载 shadow root 的组件,现在是把它们重写到 HTML 里的时候了。

评论区

0 条评论

登录后可评论。

阿柯·前端架构 71 阅读