先说一个核心判断:在 HTML 中,id 的作用是唯一标识一个元素,相当于每个节点的专属身份证,它并非为样式复用而设计。这一点,很多开发者起初会觉得"反正功能上也能用",但实际踩坑多了,就会明白为什么坚持使用 class 才是正确做法。

为什么不能用 id 做样式复用基类
先看一个最简单的问题:如果你把同一个 id 用在多个元素上,document.getElementById() 只会返回第一个匹配项——剩下的那些元素,JavaScript 根本无法获取。这还只是冰山一角。无障碍工具会报错,CSS 选择器的表现也会变得难以预测,特别是当你搭配 :focus-within 或 label[for] 这类属性时,行为很可能完全偏离预期。
更让人头疼的是,你写一个 #card { padding: 1rem; },页面里有 5 个 id="card",结果样式只对第一个生效。其余几个看起来就像没加样式一样,但你很难第一时间意识到是 id 冲突——它既不报错,也不警告,就这么悄无声息地坑你。
class天生就是为复用而设计的,可以重复使用,可以组合搭配,也可以叠加效果- 语义化类名如
card、btn、form-field,才是真正可继承的基类起点 - 脱离标签名和层级来做基类,比如用
article h2,结构一旦调整,样式链条就会断裂
本身不提供样式基类,但它是结构复用的起点
标签只做一件事:定义一个 DOM 片段。它不会解析、不会渲染、也不会自动套用样式。所以你不能指望在里面放一个 ,样式就自动生效——前提是页面中必须存在 .card 的定义。
这引出一个关键认知:模板复用,不等于样式复用。你需要单独维护一套可复用的 CSS 类体系,并且确保所有使用该模板的地方都引入了对应的样式文件或内联样式块。
- 推荐在模板内使用语义化的 class,比如
- 不要依赖外部作用域的 class 名,比如
——这个container可能根本没有定义 - 如果需要隔离样式,得手动采用
scoped策略(比如 Shadow DOM),但原生并不支持这个特性
如何让模板里的 class 真正成为可继承的样式基类
核心思路其实很朴素:把 class 当成一份契约。模板声明"我需要 .card、.card-title 这些类存在",样式层负责兑现。不是模板驱动样式,而是样式驱动模板行为。
具体怎么落地?
- 用 CSS 自定义属性统一控制基类变量,比如
--card-padding: 1rem;,然后在.card里用padding: var(--card-padding) - 用
@layer显式分层,基类放在@layer base,组件变体放@layer components,权重冲突直接避免 - 严格禁止在模板 JS 里内联写
element.style.color = '#333'——这样会覆盖所有 CSS 变量和媒体查询 - 如果模板要支持主题切换,所有颜色、间距都必须走
var(--color-primary),绝不使用硬编码
常见错误:以为把 HTML 塞进 就自动获得样式复用能力
最典型的翻车场景是:本地开发看着一切正常,部署到线上后,部分卡片没了边框、文字没有行高、按钮丢了圆角。排查一圈才发现,构建流程漏掉了某份 CSS 文件,或者 CDN 缓存了旧版样式表。模板本身不会给你任何报错提示——它就那么安静地把一堆没有样式的 div 渲染出来了。
这暴露了一个很残酷的事实:HTML 模板不会校验样式是否存在。它只管结构,不管视觉。所以样式复用必须靠人工约定加上工程约束来兜底,比如在 CI 中检查 class 是否在 CSS 里有明确定义。
最容易被忽略的场景是什么?多个团队共用同一套模板的时候。没人更新 .card-footer 的 CSS,但新业务往模板里加了一个 ——结果就是"写了等于没写",连 debug 都很难找到问题根因。
