表格 Block 名必须是业务功能名,如 user-list-table;列样式须通过 __cell--xxx Modifier 实现;表头与单元格样式需解耦;响应式隐藏列应使用 display: none + Modifier;Modifier 必须保持语义一致性。

表格 Block 名必须是业务功能名,不能是 table
直接用 table、data-table 或 grid 当 Block 名,等于主动放弃可维护性。浏览器对 tr、td 有强默认样式(比如 vertical-align: middle、border-collapse),且部分 CSS 属性(如 flex、position: absolute)在 tr 上根本无效。你写 table__row 后发现 hover 不触发、列宽错位、React 渲染后 colgroup 错行,都是这个原因。
正确做法是按真实业务切块:
-
user-list-table(用户列表) -
order-summary-table(订单汇总) -
audit-log-table(审计日志)
每个 Block 独立存在,类名搜索能精准命中,样式不跨表污染,迁移或抽离组件时也无需重命名。
列没有 DOM 节点,只能靠 __cell--xxx Modifier 表达职责
HTML 中没有“列”的真实元素,col 标签不支持伪类、背景、border,且在 Vue/React 动态渲染中极易错位。试图给“第3列”加类或用 colgroup 控制样式,本质是在对抗浏览器限制。
所有列级样式必须收口到 __cell 的 Modifier 上:
-
user-list-table__cell--status→ 控制居中、状态图标、背景色 -
user-list-table__cell--amount→ 控制右对齐、千分位、货币符号 -
user-list-table__cell--actions→ 控制按钮间距、悬停展开逻辑
修饰符名必须反映业务角色(--status),而非位置(--col3)或视觉(--blue-bg)。否则换一个表格就要重写一整套类名。
表头和单元格样式要解耦,别依赖 th/td 标签选择器
用 th 和 td 默认样式写样式,等于把语义和表现绑死。一旦某列需要禁用加粗、改变垂直对齐,就得写一堆覆盖规则;排序箭头、可编辑提示、固定列交互等逻辑也难以统一管理。
显式声明职责更可控:
-
user-list-table__header-cell:只用于表头,承载排序、筛选、固定列逻辑 -
user-list-table__cell:统一控制所有数据单元格的内边距、换行、垂直对齐 - 列对齐、字体权重等全部走 Modifier:
user-list-table__header-cell--amount、user-list-table__cell--date
排序图标这类动态内容,推荐用属性选择器补足语义:th[data-sortable].user-list-table__header-cell--name::after,避免耦合标签与状态。
响应式隐藏列必须用 display: none + Modifier,不能删 DOM
用 JS 移除 col 或条件渲染 td,会破坏 SSR 输出结构、影响焦点管理、导致屏幕阅读器行为异常。而且每次增删列都要改 HTML 和 JS,维护成本飙升。
正确方式是保持 DOM 稳定,纯 CSS 控制显示:
@media (max-width: 768px) {
.user-list-table__cell--phone {
display: none;
}
}
如果需多断点控制,可扩展 Modifier:user-list-table__cell--phone--hidden@md,配合预处理器或 PostCSS 插件生成对应规则。关键点在于:隐藏是视觉层决策,不是结构层删减。
最常被忽略的是 Modifier 的语义一致性——--status 在所有表格里都代表“状态列”,--pending 这类状态则属于行(user-list-table__row--pending),不能混挂到单元格上。一旦职责错位,后续加新表格时就只能复制粘贴、修修补补,BEM 就退化成了类名拼接游戏。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











