正确做法是用.fab--expanded表示视觉变体,.is-open管理交互状态;动画绑定在.fab__menu自身并配合.is-open控制,禁用伪类直接映射类名,确保结构、样式、行为职责分离。

如何用BEM命名规范定义FAB的交互状态类名
直接用 .fab--active 或 .fab--open 是错的——BEM不鼓励用状态词作修饰符,因为状态是临时、可叠加、可能冲突的。正确做法是把状态抽离为独立的布尔类,与结构解耦。
-
.fab是块(block),代表整个FAB容器 -
.fab__trigger是元素(element),指内部可点击的按钮或图标 -
.fab--expanded是修饰符(modifier),只用于描述“当前处于展开态”的视觉/布局变体,而非运行时状态 - 真正的交互状态应使用
.is-open、.is-disabled这类中性前缀类,它们可与其他组件共用,也方便JS动态增删
为什么不能把 :focus-within 直接当状态依据写进BEM类里
很多DaisyUI或纯CSS FAB依赖 :focus-within 实现无JS展开,但BEM类名必须反映实际DOM结构和可维护性,不能映射伪类逻辑。比如你写 .fab--focused,但这个类根本不会出现在HTML里,JS也无法操作它,调试时会丢失上下文。
- 伪类行为应由CSS单独控制,例如:
.fab.is-open .fab__menu { transform: scaleY(1); opacity: 1; } - JS只需管理
.is-open的存在与否,不关心它是怎么触发的(鼠标、键盘、还是屏幕阅读器) - 否则一旦改用JS控制展开逻辑,所有相关CSS都要重写,违背BEM“样式与行为分离”原则
.fab__menu 的展开动画该绑定在哪个类上
动画必须绑定在 .fab__menu 元素自身,而不是 .fab 块上。否则当FAB位置变化(如从右下角移到左上角),菜单动画会错位或失效。
- 错误:
.fab--expanded .fab__menu { ... }—— 修饰符在父级,动画属性却写在子级,语义断裂 - 正确:
.fab__menu { transition: transform 200ms ease, opacity 150ms ease; }+.fab__menu.is-open { transform: scaleY(1); opacity: 1; } - 如果菜单有多个子项(扇形排列),每个
.fab__item应用 stagger 动画,用nth-child或 CSS自定义属性控制延迟,避免硬编码序号
移动端点击区域扩大时,BEM结构怎么保持语义清晰
为修复iOS fixed定位抖动或提升触控容错率,常加 padding 和负 margin,但这会让HTML结构和视觉表现脱节。BEM必须守住“类名即意图”的底线。
立即学习“前端免费学习笔记(深入)”;
- 不要用
.fab--touch-friendly这种模糊修饰符;而是明确用途,如.fab--enhanced-hit-area - 把视觉扩大的逻辑封装在
.fab__trigger内部:给它加transform: translateZ(0)触发硬件加速,再用padding+margin扩大热区 - 确保
.fab__trigger仍能被屏幕阅读器识别为button或带role="button",否则扩大的只是“假按钮”
.is-open 类删了菜单就关不掉,而 .fab--large 删了只是变小,这才是修饰符和状态类的本质分野。


















