bem 命名规范要求用 .card__header、.card__body、.card__footer 显式声明结构契约,避免后代选择器导致的样式失效与耦合;子元素需独立命名如 .card__title,修饰符必须作用于块或元素本身。

直接用 .card__header、.card__body、.card__footer 三类命名,就能让卡片样式不随 DOM 结构变化而失效——这不是偷懒,而是把“结构契约”写进类名里。
为什么不能用 .card .header 这种后代选择器
后代选择器会绑定 DOM 层级,一旦卡片被嵌套进 .modal 或 .sidebar,.card .header 就可能匹配到外部同名节点;更麻烦的是,别人改了全局 .header 的 margin,你的卡片顶部间距就莫名崩掉。BEM 的 .card__header 是独立类名,不依赖父元素是否存在、是否在 DOM 某一层。
常见错误现象:
-
.card > .header—— 看似严格,但只要 HTML 里多套一层<div>,样式就断链 <li> <code>.card-header(缺双下划线)—— 工具链无法识别为 element,CSS Modules 也难做作用域隔离 - 把
.card__title和.card__subtitle写成同一层级的复用类 —— 后续想给 subtitle 单独加 transition,就得加!important覆盖 title 的 margin 规则 - 标题用
.card__title,不写.title或.card-title - 副标题用
.card__subtitle,不是.card__header-subtitle(违反 BEM 元素不可嵌套原则) - 右上角操作按钮用
.card__header-action,而非.card__action(避免和 footer 中的 action 混淆) - 需要图标时,用
.card__title-icon,不是.card__header__icon(三层命名 = 结构超限,该拆组件) - 把分页控件塞进
.card__body—— 分页本质是导航行为,应归入.card__footer或独立为.pagination组件 - 在
.card__footer里写text-align: right控制按钮位置 —— 这属于布局细节,应由.card__footer--right-aligned修饰符显式表达 - 用
.card__body p统一设置段落样式 —— 破坏 BEM 扁平性,后续加个引用块.card__quote就得额外写.card__body .card__quote来提权 - 默认状态:
<header class="card__header"></header> - 移动端折叠态:
<header class="card__header card__header--collapsed"></header> - CSS 中独立写
.card__header--collapsed规则块,不嵌套、不依赖 media 查询位置 - JavaScript 只需控制类名增删,不碰样式表逻辑
.card__header 该包含哪些子元素
Header 不是容器语义,而是功能语义:它负责承载标题、副标题、操作按钮等头部信息。所有子元素必须显式声明归属,不能靠结构推导。
正确做法:
性能提示:不用 :has() 或 :nth-child() 控制 header 布局,纯靠类名 + Flex/Grid;否则重排开销明显上升。
.card__body 和 .card__footer 的边界怎么划
Body 是内容承载区,Footer 是交互出口区——二者职责必须清晰,不能靠“看起来像”来划分。
容易踩的坑:
真实项目中,.card__body 内部可安全嵌套其他 BEM 组件(如 .avatar、.tag),只要它们不依赖 .card__body 的 CSS 规则。
响应式切换别碰媒体查询里的 .card__* 类名
在 @media (max-width: 768px) 里重写 .card__header 的 padding 或 flex-direction,等于把两种状态耦合在同一选择器下,桌面端微调就可能带崩移动端。
推荐方式:
最易被忽略的一点:修饰符(--collapsed)必须作用于 block 或 element 本身,不能挂在子元素上——比如 .card__title--collapsed 是错的,它无法表达“整个 header 折叠”,只表达了“标题自己塌了”。











