自定义主题必须使用CSS自定义属性并统一类名前缀。所有主题变量需定义在:root下,组件内仅用var()引用;类名须以c-开头,修饰符用--,子元素用__;主题切换应基于[data-theme]属性选择器,而非class切换或JS计算样式。

自定义主题必须依赖 CSS 自定义属性(--c-color-primary)而非硬编码值
直接写 color: #0066cc 或 padding: 16px 会让主题切换变成全量重写 CSS。浏览器不识别颜色名或像素值的语义,也就无法批量替换。
所有可主题化的维度——颜色、间距、圆角、字体大小、阴影强度——都得抽成 :root 下的变量:
:root {
--c-color-primary: #0066cc;
--c-space-md: 1rem;
--c-radius: 0.375rem;
--c-font-size-body: clamp(1rem, 4vw, 1.25rem);
}- 组件内只用
var(--c-space-md)、var(--c-color-primary),禁用px、em固定值 - 暗色模式只需覆盖变量:
@media (prefers-color-scheme: dark) { :root { --c-color-primary: #00aaff; } } - 第三方主题包只需提供一组变量声明,无需改 HTML 或 JS
组件类名必须带统一前缀(如 .c-button),且结构自闭合
没 Shadow DOM 时,.header、.card 这类泛化类名会立刻和项目其他样式打架。前缀不是装饰,是命名空间隔离的底线。
一个按钮组件的 HTML 必须能独立复制粘贴使用,不依赖外部容器或全局样式:
立即学习“前端免费学习笔记(深入)”;
<button class="c-button c-button--primary">提交</button>
- 所有类名以
c-开头,修饰符用--(如c-button--small),子元素用__(如c-button__icon) - 禁止出现
float-left、red-text这类样式描述名;改用u-text-danger(utility class)或变量控制 - 组件 HTML 片段里不能有裸
<div>或<span>,每个节点都要有明确语义和作用域类名
主题切换不能靠 JS 操作 class,而应靠 data-theme + 属性选择器
用 document.body.classList.toggle('theme-dark') 再写一堆 .theme-dark .c-button 规则,既难维护又易漏覆盖。CSS 层级一深就失效,JS 还得同步状态。
正确做法是把主题当作数据属性驱动:
<html data-theme="light"> <!-- 或 --> <html data-theme="dark">
- 所有主题相关样式都基于
[data-theme="dark"]选择器编写,比如:[data-theme="dark"] .c-button { background: #333; } - 切换主题只需
document.documentElement.setAttribute('data-theme', 'dark'),无副作用、可 SSR、支持伪类 - 避免在 JS 里读取
getComputedStyle判断当前主题——它返回的是计算后值,不可靠也不可逆
customElements.define() 不解决主题问题,但能隔离样式作用域
Web Components 的 shadow DOM 确实能避免样式泄漏,但它和主题系统是两层事:Shadow DOM 隔离的是组件内部样式,主题变量仍需注入到 shadow root 中才能生效。
- 在
constructor里调用this.attachShadow({ mode: 'open' })后,得手动把变量注入进去,比如:shadowRoot.innerHTML = '<style>:host { --c-color-primary: var(--c-color-primary); }</style>...' - 别指望
:host-context([data-theme="dark"])自动继承外部主题——它只对祖先元素有效,对<html>上的data-theme不响应 - 如果组件要支持主题切换,
attributeChangedCallback得监听data-theme变更,并主动更新 shadow root 内样式
主题变量注入和类名前缀这两件事,看起来是“样式规范”,实际决定了组件能否被下游项目安全复用。漏掉任何一个,都会让“支持自定义主题”变成一句空话。



















