改一个class崩三页样式是因为html缺乏语义边界和结构契约,导致css选择器脆弱、class命名混乱、role使用不当及验证缺失。

为什么改一个 class 就崩掉三页样式?
因为 HTML 结构没约束,CSS 选择器越写越脆——div > div:nth-child(2) > span:first-child 这类选择器一动就断,不是 selector 写得不够巧,是 HTML 根本没为可维护性设计。重构成本高,90% 源于早期 HTML 缺乏语义边界和结构契约。
用 role 和 aria- 属性提前划清组件边界
别等 UI 组件库封装好了再补语义,从第一行 HTML 就该明确“这是按钮组”“这是筛选区”。role 不只是给屏幕阅读器看的,它本质是给团队立下 DOM 职责契约。
-
role="navigation"必须包裹完整导航逻辑,不能只包<ul></ul>,要含搜索框、切换按钮等所有相关节点 -
aria-labelledby比aria-label更可靠:它引用真实存在的 ID,重构时只要 ID 不删,关联就不会断 - 避免
role="button"套在<div> 上还忘了加 <code>tabindex="0"和click+keyEnter双事件监听——这类“伪按钮”后期替换为原生<button></button>时,JS 逻辑常漏改class 命名不是风格问题,是接口定义
把
class当成公开 API 来设计:别人(包括三个月后的你)靠它定位、复用、覆盖。命名混乱直接导致 CSS cascade 失控,改一处样式得 grep 全局查影响。- 禁用纯样式名:
red-text、ml-16—— 它们绑定实现细节,UI 改版时全得重命名 - 推荐 BEM 变体但简化:块级容器用
search-form,内部元素用search-form__input,修饰状态用search-form--collapsed;破折号分隔比下划线更易读,也避开了 JS 变量命名冲突 - 关键:所有组件级 class 必须以组件名开头,禁止出现
btn-primary这种跨组件通用名——它迟早会和另一个组件的btn-primary冲突,最后只能靠!important救火
HTML 验证不是上线前才做的事
W3C validator 报错只是冰山一角。真正要卡的是结构契约:比如一个
data-component="tabs"的容器,必须包含且仅包含[role="tablist"]和若干[role="tabpanel"],否则 JS 初始化直接失败。- 用
html-validate配置自定义规则,例如强制img必须有alt或role="presentation",防止后期被 QA 打回来返工 - CI 中跑
npx html-validate --config .htmlvalidate.json src/**/*.html,比人眼 review 更快发现嵌套错误(如<p></p>里放<div>) <li>注意:<code>template标签内容不参与验证,但里面写的结构照样影响后续 JS 渲染——把它当真实 DOM 一样写、一样验
重构成本藏在最初 10 行 HTML 里。写的时候多花 30 秒想清楚结构职责,能省掉后面 3 小时 debug 和 2 天回归测试。最常被跳过的,永远是「这个标签到底该不该在这儿」这一问。
- 禁用纯样式名:











