时间轴bem类名必须遵循三原则:块名与文件名严格一致(如timeline.vue→timeline),元素必须直属块(禁止嵌套wrapper),修饰符仅用--且不越界;内嵌子组件须升格为独立block。

时间轴组件的 BEM 类名必须严格遵循「块独立、元素直属、修饰符不越界」三原则,否则会出现样式错位、动画失效、PurgeCSS 误删等连锁问题。
时间轴 Block 名必须与文件名完全一致
Block 是整个时间轴的物理容器,必须是可独立渲染的 DOM 节点(如 <ol class="timeline"></ol> 或 <div class="timeline">),且类名必须和文件名小写短横线对齐:<ul>
<li>
<code>Timeline.vue → Block 名只能是 timeline,不能是 time-line、tl 或 timeline-component
log-timeline.vue → Block 名必须是 log-timeline,不可复用 timeline 前缀<ol></ol> 里没加 class="timeline",后续所有 timeline__item 都失去上下文,BEM 约束即失效timeline__item 必须是 timeline 的直接子节点
Element 不表示 DOM 深度,而表示合法挂载位置。常见错误是嵌套 wrapper 导致结构断裂:
- ✅ 正确:
<ol class="timeline"><li class="timeline__item">...</li></ol> - ❌ 错误:
<ol class="timeline"><div><li class="timeline__item">...</li></div></ol>——timeline__item不再是timeline的直接子节点,CSS 选择器.timeline__item仍生效,但语义已断裂,工具链(如 stylelint-selector-bem-pattern)会报错 - ❌ 绝对禁止:
timeline__item__dot或timeline__item__content__title—— Element 不允许嵌套 Element,多级下划线会让 PurgeCSS 无法识别类名,VS Code 插件也无法跳转定义
时间轴状态类必须用 -- 修饰符,且绑定到 Block 或直属 Element
动画、折叠、高亮等交互状态必须封装为修饰符,而非独立类名或 JS 动态拼接:
- ✅ 合法:
timeline--compact(整条时间轴紧凑模式)、timeline__item--active(当前项高亮)、timeline__item--completed(已完成节点) - ❌ 错误:
timeline-item-active(被解析为新 Block,脱离上下文)、timeline__item-active(单横线,工具链无法识别为修饰符)、timeline__item__dot--filled(dot不是 timeline 的直属 Element,越界) - CSS 中每个修饰符必须显式声明动画属性:
.timeline__item--active { transform: scale(1.05); transition: transform 0.2s ease; },漏写transition会导致 JS 加类后无视觉反馈 - JS 控制时,入场动画需监听
animationend并校验event.animationName === 'item-fade-in',避免误清其他动画
时间轴内嵌子组件必须升格为独立 Block
时间轴常嵌入头像、图标、标签等复用单元,它们不能降级为 timeline__icon,而应各自成块:
- ✅ 正确:
<li class="timeline__item"> <div class="avatar avatar--sm"></div> <div class="tag tag--info">发布</div> </li> - ❌ 错误:
timeline__avatar、timeline__tag—— 这些视觉单元在用户资料页、评论区也存在,强行塞进 timeline 会破坏复用契约,后期改 avatar 尺寸需同步修所有 timeline 相关样式 - 若某图标仅在此处出现且永不复用(如时间轴专属连接线
timeline-connector),才可作为 Block 存在,命名仍需与文件名一致:TimelineConnector.vue→timeline-connector
最容易被忽略的是:BEM 的约束力只存在于类名字符串本身——一旦允许 timeline__item--large 这种修饰符作用于非 Block/Element 的中间层,或容忍 __ 出现在非直属关系中,整个组件的重构边界就模糊了。时间轴这类线性结构看似简单,恰恰最易因“图省事多嵌一层 div”导致后续所有人踩坑。











