表单应作为独立功能单元,block名须为功能名词(如.search-form),字段需拆分为自治block(如.field-email),label与input必须显式关联,修饰符应表业务状态(如--submitted)而非视觉或实现细节。

表单不是“一堆输入框的集合”,而是有明确业务边界的独立功能单元;直接套用 .form 或嵌套写 .login-form__input__icon 会立刻让样式失控、JS 绑定断裂、无障碍失效。
表单 Block 名必须是功能名词,不能是容器或结构描述
一个表单的 Block 名要回答“这是什么”,而不是“它在哪”或“它长什么样”。.login-form 可以在弹窗、侧边栏、独立页面复用;.modal-form 或 .section-form 则把布局逻辑混进了样式层,换地方就得重写 CSS 和 JS。
- ✅ 正确:
.search-form、.contact-form、.password-reset-form - ❌ 错误:
.form-container、.wrapper-form、.full-width-form - ⚠️ 注意:多个表单共用输入框/按钮样式?抽成原子块
.form-field或.form-button,别让每个 Block 重复实现
字段必须拆成独立 Block,不能塞进 form 下当元素
把所有输入框都叫 .login-form__input 看似省事,实际会让密码框加眼睛图标、邮箱实时校验等需求只能靠内联样式或 JS 拼 class 解决——这等于放弃 BEM 的可复用前提。
- 每个字段应是自治单元:
.field-email、.field-password、.field-terms -
.field-email是 Block,其内部元素为.field-email__label、.field-email__input、.field-email__error - 状态修饰符(如
--invalid)只加在 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容器 - ⚠️ 混用会导致 Cypress / axe 等自动化测试工具报错,尤其在无障碍验证环节
修饰符优先用布尔型业务状态,禁用视觉值或 JS 实现细节
表单交互频繁,修饰符容易变成“技术快照”。.login-form--loading 揭露了实现方式,下次换成骨架屏或延迟提交就失效;.login-form--submitted 描述的是确定业务阶段,更稳定、可预测。
- ✅ 推荐:
--submitted、--validated、--with-toggle(固定 UI 变体) - ❌ 避免:
--blue、--v2、--loading、--js-active - ⚠️ 多状态组合时禁止嵌套修饰符:
.button--primary--disabled是反模式,应写成.button--primary.button--disabled
最常被忽略的一点:BEM 不是给现有 HTML 贴新类名的游戏,而是重构组件边界的过程。你改一个 .field-email 的样式,不该影响到 .search-form 里的任何东西——如果影响了,说明它们本该共享某个原子块,而不是各自实现一套逻辑。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











