表单字段必须封装为独立 block,如 field-email、field-password;label 与 input 需通过 for/id 或嵌套显式关联;修饰符仅表达业务状态(如 is-invalid)或固定 ui 变体(如 --with-toggle),禁止描述样式特征或重复 block 名。

表单字段必须封装为独立 block,不能直接挂在 form 下
把 label 和 input 直接命名为 form__label、form__input 是典型错误。这类写法会让所有字段共享同一套样式作用域,一旦某个字段需要独立控制状态(比如密码框要加眼睛图标、邮箱字段要实时校验),就只能靠内联样式或 JS 拼 class —— 这破坏了 BEM 的可复用前提。
真实业务中,每个字段都应是自治单元:有自己的结构、状态、交互逻辑。所以必须为每个字段定义独立 block,例如:field-email、field-password、field-terms。
-
field-email是 block,负责整体容器布局和状态绑定(如field-email--invalid) - 其内部元素统一使用
field-email__label、field-email__input、field-email__error - 所有修饰符(
--disabled、--loading)只作用于 block 根节点,便于 JS 一次性切换整个字段状态
label 与 input 的语义关联必须显式声明,不能仅靠命名
BEM 命名本身不保证无障碍或伪类生效。field-email__label 和 field-email__input 即使名字匹配,若 HTML 中没建立真实 DOM 关联,:focus-within 不会触发,屏幕阅读器也无法读出对应关系。
有两种合法方式建立关联,但二者不可混用:
- 显式
for/id绑定:<label for="field-email__input">邮箱</label>+<input id="field-email__input" class="field-email__input">,且id必须与 element 名一致 - 嵌套结构:
<label class="field-email__label">邮箱<input class="field-email__input"></label>,此时无需id,但field-email__label和field-email__input必须同属一个field-email容器内
混用(一半用 for 一半嵌套)会导致自动化测试工具无法识别控件关系,尤其在 Cypress 或 axe 测试中报错。
修饰符只表达状态,不描述样式特征
写成 field-email__input--large 或 field-email__label--bold 是误用。BEM 修饰符不是 CSS 工具类,它表达的是“这个字段当前处于什么业务状态”,而不是“它看起来有多大/多粗”。
正确做法:
- 状态类用
is-前缀:is-invalid、is-disabled、is-filled,它们可跨组件复用,且与 block 解耦 - 视觉变体用
--修饰符:field-email--compact、field-password--with-toggle,这些是固定、可控的 UI 变体,不应随用户输入动态切换 - 布局或尺寸控制交给设计系统 utility class(如
u-width-full),而非塞进 BEM 名字里
嵌套子元素命名禁止重复 block 名
常见错误是写成 field-password__input-icon 或 field-password__input-wrapper —— 这违反 BEM 元素命名原则:element 名只需说明“它是什么”,不需重复上下文。
正确命名只保留语义本质:
-
field-password__icon(不是field-password__input-icon) -
field-password__wrapper(不是field-password__input-wrapper) - 若图标有多种类型,用 modifier:
field-password__icon--toggle、field-password__icon--status
更复杂结构(如带前后缀的输入框)应仍保持扁平层级:field-search__input、field-search__prefix、field-search__suffix,全部挂载在 field-search 下,不出现 __input__suffix 这类三段式命名。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











