html class/id冲突无法通过git merge解决,因其是全局扁平命名空间,合并仅处理文本而非语义;bem(如user-profile__modal)是唯一可落地的隔离方案,需配合构建前缀、运行时作用域限定及工具链协同预防。

没有“自动合并规范冲突”的方案,所有 HTML 规范冲突都必须靠构建时注入前缀 + 运行时作用域限定 + 工具链协同来预防,而不是靠后期 merge。
class/id 冲突为什么不能靠 Git merge 解决
HTML 的 class 和 id 是全局 flat 命名空间,git merge 只能合并文本行,无法识别语义冲突。比如团队 A 提交了 class="modal",团队 B 也提交了 class="modal",Git 会安静地合入,但上线后两个组件样式互相覆盖——这不是合并失败,是合并成功后的必然崩溃。
- 常见错误现象:主应用引入两个第三方组件库,都用了
class="tooltip",一个显示在左上角,一个强制 fixed 在右下角,最终只生效后者 - BEM 是唯一可落地的解法:
user-profile__modal和shop-cart__modal天然隔离,不依赖构建工具也能肉眼分辨归属 - 禁止用通用修饰符如
is-active或hidden:它们没绑定到具体 block,一旦多个组件共存,状态类就互相干扰
data-* 属性命名必须带业务上下文,否则等于裸写
data-id、data-name 这类泛化名在多团队协作中毫无意义,它不是技术限制,而是契约失效——前端不知道这个 ID 是用户 ID、SKU 还是 session token,后端也不知道该字段由哪个前端模块消费。
- 安全写法:
data-user-id、data-product-sku、data-order-timestamp - JS 中读取时自动转驼峰:
el.dataset.userId对应data-user-id,但前提是命名本身有业务指向 - stylelint 的
selector-attribute-pattern规则可强制校验:"^data-[a-z]+-[a-z]"拒绝data-id类裸名 - 别把多个字段塞进单个
data-state:更新一个字段就得重写整个字符串,竞态风险高且不可 diff
自定义元素注册必须前置 + 带破折号 + 统一前缀
浏览器强制要求 customElements.define() 的第一个参数含破折号,这是语法硬约束;而前缀(如 shop-、user-)是协作层面的最低成本防御手段。
- 非法名:
mybutton、MyButton、my_button→ 直接抛DOMException: The element name is not valid - 注册时机关键:必须在标签首次渲染前完成;若 DOM 已存在,需手动调用
customElements.upgrade() - 前缀不是可选项:两个团队都注册
modal,哪怕加了破折号(modal-elementvsmodal-widget),仍可能撞车;统一约定teamA-modal、teamB-modal才可靠 - 避免和标准元素冲突:别用
my-article、shop-header,优先选更具体的语义,如user-profile-card
CSS 与 JS 隔离边界必须物理对齐,否则隔离形同虚设
只改 HTML class 名但 JS 还用 document.getElementById("modal"),或 CSS 写了 .user-profile__header 但 HTML 漏了根节点 class="user-profile",隔离就立刻失效——这不是 bug,是人为打破约定的必然结果。
- JS 查询必须限定在组件根节点内:
rootEl.querySelector(".user-profile__submit-btn"),禁用全局document.querySelector - 根元素必须有唯一 block class,且所有子元素、状态类严格遵循 BEM:
user-profile--loading而非is-loading - 若用 Shadow DOM,隔离天然成立,但代价是:
document.querySelector(".tooltip")拿不到内部节点,getComputedStyle无法获取计算样式 - 没上 Shadow DOM 时,“根节点 class + BEM + JS 作用域限定”是唯一防线,跨过一次,冲突就从“可能”变成“必然”
真正难的不是写对某一行 class,而是让每个团队成员在每次新增组件时,本能地写出带前缀的 block 名、带双下划线的子元素、带双短横的状态类,并在 JS 里自觉限定查询范围——这需要工具链兜底(Prettier + stylelint + customElements 注册检查),而不是靠 CR 时口头提醒。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











