关于 bem-structure
bem-structure 是指导 AI 按 BEM 方法编写和审查 CSS 的技能,面向维护前端样式的开发者。它强调语义化命名、明确选择器,并优先复用 RoleModel 的 Optics 组件。
主要功能
- 01BEM 块、元素与修饰符规范
- 02明确且语义化的类名
- 03避免标签、ID 和层级选择器
- 04修饰符使用显式选择器
- 05优先复用 Optics 组件
适用场景
- 01为新界面编写 BEM 样式
- 02重构或审查现有 CSS
- 03修复不符合 BEM 的类名
- 04判断是否应复用 Optics 组件
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ rolemodel/ skills --skill bem-structure安装后在 Claude Code 中输入/bem-structure确认已加载。
详细介绍
概述
这项技能指导 AI 使用 BEM(Block Element Modifier)方法编写 CSS,通过清晰的命名约定和组件结构,创建易于维护、可扩展且可复用的样式表,同时判断其作用范围、风险和架构影响。还应将 BEM 与我们的 RoleModel 设计系统 Optics 配合使用,避免重复创建已有内容。如果已有适用的 Optics 组件,就应使用它,必要时进行覆盖,而不是创建新的 BEM 块。
Agent 应优先考虑清晰性、可预测性,并尽量减少意外副作用。
关键词:CSS 审查、BEM 结构、BEM 方法、CSS 最佳实践、重构 CSS、审查 CSS、修复我的 CSS、修复我的 BEM、将我的 CSS 转换为 BEM
什么是 BEM?
BEM 是 Block Element Modifier 的缩写——一种帮助你在前端开发中创建可复用组件并共享代码的方法。
| 模式 | 语法 | 示例 |
|---|---|---|
| 块 | .block | .card |
| 元素 | .block__element | .card__title |
| 块修饰符 | .block--modifier | .card--elevated |
| 元素修饰符 | .block__element--modifier | .card__title--large |
| 多词名称 | .block-name | .user-profile |
命名约定
- 与其他开发工作一样,名称应清晰表达意图。
- 在 BEM 中,命名要表达的意图并非所应用的样式或外观,而是它在界面中的用途。
- 具体的样式通常不适合作为名称,但修饰符除外(small、large、padded 等)。
- 某些情况下,可以根据具体工作流命名(如带日期的日历)。
- 根据具有共同类型的工作流命名,通常最为合适(form、table、card、button)。
- 不一定要根据更广泛的 UI 抽象命名,但在无需上下文的抽象场景中可以这样做(primary、large 等)。
- 名称应足够具体,能够清晰表达用途;如适用,也应足够通用,以便复用。并非总是能够或适合复用,因此不要过度追求通用性。
- 尽量使用明确、不易产生歧义的名称。修饰符尤其需要注意这一点。
- 使用扁平的 BEM 类,并在修饰符中显式使用
&。 - DOM 结构无需遵循 CSS 类结构。
如果因项目限制或其他原因无法遵循这些指南,请在聊天输出中说明偏离的原因。
基本语法
✅ 正确(请这样做)
.block {
.block__element {
&.block__element--modifier { }
}
&.block--modifier { }
}
<div class="block">
<div class="block__element">...</div>
<div class="block__element block__element--modifier">...</div>
</div>
<div class="block block--modifier">
<div class="block__element">...</div>
<div class="block__element">...</div>
</div>
🚫 错误(不要这样做)
.block {
.block--modifier { } /* Use `&` before all Modifier class names */
}
.block_element { /* Use `__` between Blocks and Elements and nest Element within the Block */
&.block__element-modifier { } /* Use `--` between the Modifier and its Element */
}
<div class="block">...</div>
<div class="block__element">...</div>
<div class="block__element--modifier">...</div>
</div>
<div class="block__element">
<div class="block__element">...</div>
</div>
规则摘要
- 所有类名都必须是完全显式的 BEM。可以嵌套以便组织代码,但选择器不应依赖标签名或 ID。
&只能用作对完整选择器的文本引用。- 不得使用
&构造类名(&--、&__)。 - 嵌套仅用于组织代码;必须使用显式的 BEM 类名。可以使用嵌套选择器,将元素限定在其块的范围内。
- 可以使用
&,将修饰符与其块或元素放在一起,同时保持选择器显式。
✅ 正确(请这样做)
.card {
&.card--featured {}
&.card--compact {}
&.card--featured {
&.card--compact {}
}
}
🚫 错误(不要这样做)
.card {
&--featured {}
&__title {}
&__title--large {}
}
块
封装一个本身具有意义的独立实体。块可以相互嵌套和交互,但在语义上彼此平等,不存在优先级或层级关系。没有 DOM 表示的整体实体(例如控制器或模型)也可以是块。
命名:
块名可以由小写拉丁字母、数字和连字符组成。创建 CSS 类时,添加简短前缀以进行命名空间划分:.block。较长块名中的空格应替换为连字符。
HTML:
任何接受类名的 DOM 节点都可以是块。
✅ 正确(请这样做)
<div class="card">...</div>
<div class="button">...</div>
<div class="menu">...</div>
<div class="header">...</div>
<div class="search-form">...</div>
<div class="user-profile">...</div>
<div class="modal">...</div>
<div class="navigation">...</div>
<div class="dropdown-menu">...</div>
🚫 错误(不要这样做)
<div class="searchForm">...</div>
<div class="button_primary">...</div>
<div class="userProfile">...</div>
<div class="dropdown__menu">...</div>
CSS:
仅使用类名选择器。不要使用标签名或 ID,也不要依赖页面上的其他区块或元素。
✅ 正确(这样做)
.card { }
.button { }
.menu { }
.header { }
.search-form { }
.user-profile { }
.modal { }
.navigation { }
.dropdown-menu { }
🚫 错误(不要这样做)
.searchForm {}
.button_primary {}
.userProfile {}
.dropdown__menu {} /* Don't use element syntax for blocks */
}
元素
区块的组成部分,不具有独立含义。任何元素在语义上都与其所属区块相关联。
命名:
元素名称可以由小写拉丁字母、数字、连字符和下划线组成。CSS 类名由区块名称、两个下划线和元素名称组成:.block__elem。较长元素名称中的空格应替换为连字符。
HTML:
区块内的任何 DOM 节点都可以是元素。在给定区块中,所有元素在语义上都是平等的。CSS 中的元素不应在其所属区块之外使用。
✅ 正确(这样做)
<div class='block'>
<div class='block__element'>
<div class='block2'>
<div class='block2__element'>...</div>
</div>
</div>
</div>
🚫 错误(不要这样做)
<div class='block'>
<div class='block__element'>
<div class='element__element'>...</div>
</div>
</div>
CSS:
在 CSS 中,元素应嵌套在其所属区块内。结构不必与 DOM 结构一致。
✅ 正确(这样做)
/* Card block with elements */
.card { /* This is the block; elements are inside */
.card__header { }
.card__title { }
.card__body { }
.card__footer { }
.card__image { }
}
/* Menu block with elements */
.menu {
.menu__item { }
.menu__link { }
.menu__icon { }
}
/* Search form block with elements */
.search-form {
.search-form__input { }
.search-form__button { }
.search-form__label { }
}
🚫 错误(不要这样做)
/* Don't create deeply nested element names */
.menu {
.menu__item { }
.menu__item__link { } /* Improper naming structure */
.menu__item__link__icon { } /* Improper naming structure */
}
修饰符
区块或元素上的标记。使用它们来更改外观、行为或状态。
命名:
修饰符名称可以由小写拉丁字母、数字、连字符和下划线组成。CSS 类名由区块或元素名称加上两个连字符组成:.block--modifier 或 .block__elem--modifier,以及 .block--color-black 和 .block--color-red。复杂修饰符名称中的空格应替换为连字符。
在以下情况下,应使用修饰符,而不是创建单独的元素:
- 更改只是简单的状态变化(例如,激活、禁用、高亮)
- 更改只是简单的外观变化(例如,尺寸、颜色、布局)
- 更改不会引入需要额外元素的新内容或功能
如果元素有默认状态和另一种可作为修饰符的状态,请将默认样式添加到基础元素,并在应用修饰符时使用修饰符覆盖这些样式。不要为默认状态创建专属元素,也不要在这种情况下创建两个修饰符。
🚫 错误(不要这样做)
.product-card__image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.product-card__placeholder {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, var(--op-color-neutral-plus-six) 0%, var(--op-color-neutral-plus-seven) 100%);
}
✅ 正确(这样做)
.product-card__image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
&.product-card__image--placeholder {
object-fit: unset;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, var(--op-color-neutral-plus-six) 0%, var(--op-color-neutral-plus-seven) 100%);
}
}
HTML:
修饰符是添加到区块或元素 DOM 节点上的额外类名。只将修饰符类添加到其所修饰的区块或元素上,并保留原有类名。需要明确的是,修饰符类应始终与其基础区块或元素类搭配使用。
✅ 正确(这样做)
<div class="block block--modifier">...</div>
<div class="block block--size-big block--shadow-yes">...</div>
🚫 错误(不要这样做)
<div class="block--modifier utility">...</div>
CSS:
✅ 正确(这样做)
.menu {
.menu__item {
&.menu__item--active { }
}
.menu__link { }
.menu__icon { }
&.menu--padded { }
}
🚫 错误(不要这样做)
.menu {
.menu__item {
.menu__item--active { } /* No ampersand */
}
.menu__link { }
.menu-link-active { } /* Bad name structure */
.menu__icon { }
.menu__padded { } /* Improper modifier structure; should be using `&` and `--`, not `__` */
}
其他规则
- 仅使用类名(不使用 ID)
- 仅使用扁平类名和选择器
- 不基于标签设置样式
- 不基于 DOM 层级设置样式
- 每个区块只承担一种概念职责
- 区块可以根据需要包含其他区块
- 元素不能脱离其所属区块
- 多词名称使用 kebab-case:
.user-profile、.dropdown-menu - 元素名称中使用双下划线(
__)分隔区块和元素 - 修饰符名称中使用双连字符(
--)分隔区块/元素和修饰符 - 名称应具有语义、描述性并能体现意图(而非基于外观)
- 避免使用不被普遍理解的缩写
语法示例
假设有一个表单区块,带有修饰符 theme: "xmas" 和 simple: true,并包含 input 和 submit 元素;submit 元素还有自己的修饰符 disabled: true,用于在表单未填写完整时阻止提交:
✅ 正确(这样做)
<form class="form form--theme-xmas form--simple">
<input class="form__input" type="text" />
<input
class="form__submit form__submit--disabled"
type="submit" />
</form>
.form {
.form__input { }
.form__submit {
&.form__submit--disabled { }
}
&.form--simple { }
&.form--theme-xmas { }
}
🚫 错误(不要这样做)
<form class="form form-simple form--theme-xmas ">
<input class="form_input" type="text" />
<input
class="form__submit--disabled"
type="submit" />
</form>
.form {
.form__input { }
.form_submit { /* Use `__` between Block and Element */
.form__submit--disabled { } /* Use `&` before all Modifier class names */
}
&.form-simple { } /* Use `--` between Element and Modifier */
}
&.form--theme-xmas { } /* Must nest Elements and Modifiers within Block */