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,自定义属性命名正则

返回技能库 更多技能入口