BEM:CSS 命名规范 作者:马育民 • 2026-08-20 14:51 • 阅读:10017 # 介绍 BEM:**Block(块)‑Element(元素)‑Modifier(修饰符)**,是一套组件化 CSS 命名约定,解决类名冲突、样式耦合、语义不清晰问题,适合大型项目。 # 一、概念 ### 1. Block 块 **独立、可复用的组件块**,代表一个整体模块,不依赖其他组件。 - 命名:使用**小写字母,连字符 `-` 连接多单词** - 特征:可以独立使用 示例: ```css /* 块:卡片、按钮、导航栏 */ .card {} .nav-bar {} .search-form {} ``` ✅正确:`.user-card` ❌错误:`.UserCard`(不要驼峰)、`.userCard`(不要小驼峰) ### 2. Element 元素 **块内部的子部分,不能脱离块单独使用**。 - 语法:`block__element`,使用**两个下划线 `__`** 分隔块和元素 - 含义:属于某个块的子元素,脱离块就没有意义 ```css .card__title {} /* card块里的标题 */ .card__content {} /* card块里的内容 */ .card__btn {} /* card块里的按钮 */ .nav-bar__item {} /* 导航栏的菜单项 */ ``` > 不允许多层嵌套 `block__elem1__elem2`! ❌错误:`.card__header__title` ✅正确:`.card__header-title`(多单词用单横线,只用一次`__`) ### 3. Modifier 修饰符 **用来描述块/元素的状态、变体、外观**(尺寸、颜色、激活、禁用、选中)。 - 语法:`block--modifier` 或者 `block__element--modifier`,**两个短横线 `--`** - 修饰符本身不单独存在,必须依附块或元素 ```css /* 块的修饰符 */ .card--dark {} /*深色版本卡片*/ .btn--primary {} /*主按钮*/ .btn--disabled {} /*禁用状态按钮*/ /*元素的修饰符*/ .nav-bar__item--active {} /*导航激活项*/ .card__btn--large {} /*卡片内大按钮*/ ``` --- # 二、语法 ``` 块:block-name 元素:block-name__element-name 修饰块:block-name--modifier-name 修饰元素:block-name__element-name--modifier-name ``` ### HTML示例完整演示 ```html <!-- BEM示例:卡片组件 --> <div class="card card--dark"> <div class="card__header"> <h3 class="card__title">标题</h3> </div> <div class="card__content">内容文本</div> <button class="card__btn card__btn--primary">确定</button> </div> ``` ```css /*块*/ .card { border:1px solid #eee; } /*块修饰符*/ .card--dark { background:#222; color:#fff; } /*元素*/ .card__header { padding:10px; } .card__title { font-size:16px; } .card__btn { padding:6px 12px; } /*元素修饰符*/ .card__btn--primary { background:#1677ff; color:#fff; } ``` 关键点:**修饰符类永远和基础类同时写在标签上,不要单独写修饰符类**。 ❌ `<div class="card--dark">` ✅ `<div class="card card--dark">` --- # 三、命名多单词规则 - 块、元素、修饰符内部多个单词:用**单横线 `-`** - 块与元素分隔:**双下划线 `__`** - (块|元素)与修饰符分隔:**双横线 `--`** 示例: ``` .user-profile 块:用户资料 .user-profile__avatar 元素:用户资料的头像 .user-profile__avatar--large 修饰:大尺寸头像 ``` --- # 四、BEM常见误区 ### 1. ❌不要无限嵌套`__` ``` //错误 .card__header__title{} //正确 .card__header-title{} ``` ### 2. ❌修饰符不能单独使用 修饰符只是追加样式,基础类必须保留。 ### 3. ❌不要把页面结构当块 块是可复用组件,不是页面布局容器;页面布局可以单独写布局类。 ### 4. ❌不要 DOM 结构和 BEM 强行绑定 BEM是组件语义,不是html层级;DOM嵌套深不代表要多加`__`。 ### 5. ✅允许块嵌套另一个块 一个块内部可以放另一个独立块: ```html <div class="card"> <div class="search-form"></div> <!-- search-form是独立块,不用写card__search-form --> </div> ``` 如果这个search-form只是card内部专属、不能单独拿出去用,才写成`card__search-form`。 --- # 五、BEM的优缺点 ### ✅优点 1. **语义化**:看类名就知道属于哪个组件,是什么角色,什么状态 2. **避免选择器冲突**,减少权重滥用,少用`!important` 3. 组件化,方便复制、迁移、复用组件 4. 便于团队协作,统一命名习惯,大项目维护友好 5. 和css module、scss配合非常适配 ### ❌缺点 1. 类名很长,html标签会比较臃肿 2. 新手容易滥用`__`,过度嵌套命名 3. 需要严格遵守约定,团队要统一认知 # 六、DOM多层嵌套的写法 **HTML嵌套,跟BEM的`__`没关系!DOM嵌套 ≠ BEM嵌套,**`__`只能出现一次,不能写 `a__b__c`。 ### 场景举例:DOM是三层嵌套 ```html <div class="card"> <!-- block:card --> <div class="card__head"> <!-- element --> <div> <h2>标题</h2> <!-- DOM深层嵌套 --> </div> </div> </div> ``` ❌错误写法(跟着DOM层级多加`__`) ```css .card__head__title {} /*禁止双下划线叠加*/ ``` ✅正确:元素内部多单词用**单横线 `-`** ```html <div class="card"> <div class="card__head"> <div> <h2 class="card__head-title">标题</h2> </div> </div> </div> ``` ```css .card {} .card__head {} .card__head-title {} /* 一次__,后面用单横线 */ ``` 规则:`block__xxx-yyy` - `__`:**仅1次**,分割块和第一级子元素 - 后面再细分,全部用普通 `-`,不要再加 `__` --- ### 案例2:更深DOM层级例子 HTML DOM结构(4层标签嵌套) ```html <div class="modal"> <div class="modal__wrapper"> <div class="modal__wrapper-inner"> <div class="modal__wrapper-inner-content"> <h3 class="modal__wrapper-inner-title">弹窗标题</h3> </div> </div> </div> </div> ``` CSS: ```css /* block */ .modal {} /* element,__只写一次,后面全部单横线 */ .modal__wrapper {} .modal__wrapper-inner {} .modal__wrapper-inner-content {} .modal__wrapper-inner-title {} ``` **注意:** `modal__wrapper-inner-title` 不要写成 `modal__wrapper-inner-content-title`,**不需要把完整 DOM 路径全部拼接进类名**。类名超长,DOM 改一层,类名就要大改,维护灾难。 ## 两种嵌套区分:「组件内部子元素」vs「嵌入另一个独立组件」 ### 情况A:这个子模块只属于父块,拿出去不能用 → 用 `block__xxx-yyy` ```html <div class="card"> <div class="card__footer"> <button class="card__footer-btn">按钮</button> </div> </div> ``` ```css .card {} .card__footer {} .card__footer-btn {} ``` ### 情况B:里面是完全独立组件,可以拿出来到处复用 → **不要再加父块前缀,直接用自己的block** ❌不要写成 `.card__button` ✅直接写 `.button` ```html <div class="card"> <div class="card__footer"> <button class="button button--primary">确认</button> </div> </div> ``` ```css .card {} .card__footer {} .button {} .button--primary {} ``` --- ## ❌禁止操作汇总 1. 禁止多个`__` ```css /* 错 */ .modal__a__b__c {} /* 对 */ .modal__a-b-c {} ``` 2. 不要用后代选择器去规避BEM(很多人图省事这么写,BEM不推荐) ```css /* 不推荐,增加权重,破坏BEM扁平思想 */ .modal .modal__wrapper .title {} /* 推荐:直接给标签挂类名 */ .modal__wrapper-title {} ``` BEM思想:**尽量给需要样式的DOM节点直接挂class,少依赖DOM层级关系选择样式**,就算HTML嵌套很深,每个需要样式的节点直接写完整BEM类名。 # 七、好处 解决大型项目 CSS 混乱、选择器权重打架、命名冲突、组件不好复用的问题。 1. 类名自带语义,看 class 就知道是什么 2. **彻底减少样式冲突** 3. CSS 选择器扁平,权重可控,少用 `!important` 4. 组件可复制、迁移复用 5. HTML 结构改变,CSS 不容易坏 6. 团队协作统一,降低沟通成本 7. 和 CSS Module / Vue scoped / Tailwind 之外的传统项目适配很好 # 总结 - 块内单词单横杠,块元之间双下划; - 状态变体双横杠,修饰永远不独行; - 下划线只准一次,独立块不要套进元素。 - HTML随便嵌套几层,BEM的`__`最多出现一次; - 后续细分全部 `-`; - 内部如果是独立组件,直接用自己的块,不要加父块前缀。 原文出处:/show_1GW3tevNKBwm.html