CSS 架构(BEM 等)
让 Agent 在 BEM、ITCSS、CSS Modules 或 utility-first 方案下新增样式,明确层叠顺序与全局入口边界;本页用目录、流程图与小型实验室对齐写法。
SKILL 需声明块/元素/修饰符写法(或项目等价物)、禁止的选择器类型(如过深嵌套、标签全局选择),以及 @layer 或 import 顺序若已采用。
与 JS 框架结合时写明 CSS Modules 的 :global 使用门槛、styled-components 的主题注入方式,避免同一视觉混用多种范式导致特异性战争。
对第三方组件覆盖:要求优先用公开 API、变量或 wrapper 类,并记录「不得已使用 !important」的审批条件。
- Stylelint 规则:与命名、嵌套深度、自定义属性约定对齐。
- 关键 CSS 或构建拆分:若存在,说明 Agent 不应把大块样式写进错误入口。
- 设计 Token:颜色与间距引用方式与设计系统技能交叉引用。
样式扩展主流程(skill-flow-block)
[ 读 SKILL:命名范式、禁止选择器、入口文件 ]
│
▼
┌─────────────┐ 选 BEM 或项目等价(如 SUIT、rscss)
│ 定作用域与类名 │──── 禁止裸标签、过深后代;组件根块唯一
└─────────────┘
│
▼
┌─────────────┐ @layer 顺序 / ITCSS 层 / import 拓扑
│ 落在正确层级 │──── 新样式不跳进「工具层之上」除非 SKILL 允许
└─────────────┘
│
▼
┌─────────────┐ Modules:默认局部;:global 需理由
│ 框架边界检查 │──── 第三方:API → 变量 → wrapper → 最后才硬覆盖
└─────────────┘
│
▼
┌─────────────┐ Stylelint + 审查清单;例外写入 SKILL
│ 校验与文档化 │──── !important 与深度选择器须可追溯
└─────────────┘
流程要点:先锁命名与层级,再写具体规则;若团队已用 @layer,Agent 新增样式必须落在 SKILL 指定的层名内,避免事后用更高特异性「抢救」。
BEM 命名完整示例
/* BEM 命名:块/元素/修饰符完整规则示例 */
/* 块(Block):独立可复用的根节点 */
.card { ... }
.nav-menu { ... } /* 多词块名用连字符 */
/* 元素(Element):仅属于该块,用双下划线 */
.card__title { ... }
.card__body { ... }
.card__footer { ... }
.nav-menu__item { ... }
.nav-menu__link { ... }
/* 修饰符(Modifier):块或元素的变体,用双连字符 */
.card--compact { ... } /* 块修饰符 */
.card--featured { ... }
.card__title--muted { ... } /* 元素修饰符 */
.nav-menu__item--active { ... }
/* ✅ 正确:扁平结构,类名表达职责 */
<div class="card card--featured">
<h2 class="card__title">标题</h2>
<div class="card__body">内容</div>
</div>
/* ❌ 错误:结构耦合选择器(高特异性 + 脆弱)*/
/* .card .title { } — 不是 BEM,依赖 DOM 层级 */
/* .card--compact--blue { } — 链式修饰符,应改为两个类并存 */
/* 与 utility 类混用约定(需团队统一)*/
/* 允许:布局/间距用原子类 */
<div class="card mt-4 mb-2"> <!-- mt/mb 来自 utility,card 是 BEM 块 -->
/* 不允许:颜色/字体用 utility 替代 BEM 修饰符(导致 BEM 修饰符作废)*/
- 元素名应表达职责(
__title)而非 DOM 标签(__h2)。 - 多修饰符时允许多类并存(
.card .card--compact .card--dark),而非链式--compact--dark。
@layer 层叠层使用示例
/* @layer 声明层顺序:后声明的层优先级更高 */
@layer reset, tokens, base, components, utilities;
/* reset 层:最低优先级 */
@layer reset {
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; }
}
/* tokens 层:CSS 变量,无选择器特异性问题 */
@layer tokens {
:root { --color-brand: #3b82f6; --space-4: 1rem; }
}
/* components 层:BEM 组件样式 */
@layer components {
.card { padding: var(--space-4); border-radius: 0.5rem; }
.card--elevated { box-shadow: var(--shadow-md); }
}
/* utilities 层:最高优先级,单类覆盖 */
@layer utilities {
.mt-4 { margin-top: var(--space-4) !important; } /* utility 可用 !important */
.sr-only { position: absolute; clip: rect(0,0,0,0); }
}
/* 未分层样式(无 @layer)优先级高于所有层 ← 第三方库覆盖点 */
.third-party-override { color: var(--color-brand); }
- Agent 改动前应打开 SKILL 中的「层清单」:新文件应
@layer到哪一层,或应挂在哪个 partial 之后。 - 特异性策略:优先单层类选择器;需要提高权重时调整层顺序,而非随意嵌套后代。
CSS Modules 与 CSS-in-JS 对比
/* CSS Modules:默认局部化,构建时生成唯一类名 */
/* Card.module.css */
.card { padding: var(--space-4); } /* → .Card_card__xyz 唯一类 */
.title { font-size: var(--font-size-lg); }
/* 全局泄漏:必须标注原因 */
:global(.third-party-class) { color: red; } /* 原因:第三方库需要此类名作为钩子 */
// Card.tsx(React)
import styles from './Card.module.css';
const Card = () => <div className={styles.card}><h2 className={styles.title}>...</h2></div>;
// CSS-in-JS(styled-components):主题 token 从单一来源注入
import styled, { ThemeProvider } from 'styled-components';
const StyledCard = styled.div`
padding: ${({ theme }) => theme.space[4]}; /* 从 ThemeProvider 获取 */
border-radius: ${({ theme }) => theme.radii.md};
/* ❌ 不要写死:padding: 16px — 与 CSS 变量双轨漂移 */
`;
// CSS Modules vs CSS-in-JS 选择:
// CSS Modules:零运行时开销,构建时提取,适合 SSR 项目
// CSS-in-JS:动态主题/props 驱动样式,运行时成本,适合设计系统
- CSS-in-JS:主题 token 从单一来源注入,避免同一 token 在运行时与静态 CSS 变量双轨漂移。
- 覆盖第三方:先查组件文档的
classNames/ slot / CSS 变量;wrapper 加 BEM 块比直接改库内部类名更耐升级。
Stylelint、Token 与关键 CSS
- Stylelint:max-nesting-depth、selector-max-id、自定义属性命名与 BEM 正则应对齐 SKILL。
- 关键 CSS:若构建会内联 critical path,Agent 不应把仅用于页脚的规则写进 critical 入口。
- 设计 Token:间距与色值引用
var(--space-*)等,禁止魔法数散落(除非 SKILL 允许例外目录)。
BEM 类名拼装实验室
按常见 BEM 约定生成单条类名字符串(不含空格多类),便于粘贴到 SKILL 示例或组件模板;块名为必填,元素与修饰符可选。
规则:.{block}、.{block}__{element};修饰符接在块或元素后:--{modifier}。输入会自动压成小写并压缩非法字符为连字符。
---
name: css-architecture
description: 按 BEM/@layer/CSS Modules 约定扩展样式并控制层叠与作用域
---
# 命名范式
1. BEM:.block、.block__element、.block--modifier,元素名表达职责
2. 禁止:裸标签全局选择器、超过3层后代嵌套、链式修饰符 --a--b
3. 多修饰符:多类并存(.card .card--compact .card--dark),而非链式
# 层叠控制
4. @layer 声明顺序:reset → tokens → base → components → utilities
5. 新样式必须落在 SKILL 指定的层名内,不跳层
6. utility 层可用 !important(层内唯一例外)
7. 未分层样式优先级高于所有层,第三方库覆盖时利用此特性
# 框架与作用域
8. CSS Modules:默认局部,:global 需注释原因(第三方钩子类等)
9. CSS-in-JS:主题 token 从 ThemeProvider 单一来源注入,禁止写死值
10. CSS Modules vs CSS-in-JS:前者零运行时优先 SSR,后者动态 props 驱动
# 第三方覆盖
11. 优先:组件 classNames/slot/CSS 变量 API
12. 次选:wrapper BEM 块添加覆盖样式
13. 最后:直接覆盖内部类名(记录 PR 链接与升级风险)
14. !important 必须有可追溯原因,写入 SKILL 豁免列表
# 质量
15. Stylelint 规则:max-nesting-depth ≤ 3,selector-max-id ≤ 0,自定义属性命名正则