前端工程化第一步:BEM 国际命名规范与 CSS Reset 实战

写页面最怕什么?命名难、样式乱、维护痛。本文带你从零掌握 BEM 命名规范和 CSS Reset,让你的代码结构清晰、可维护性拉满。


一、为什么你的 CSS 总是一团糟?

刚入门前端时,我们通常会这样写 CSS:

css 复制代码
.title { font-size: 20px; }
.red { color: red; }
.box { margin: 10px; }

看起来没什么问题,但当页面变复杂后:

  • .title 是哪个区块的标题?
  • .red 今天红明天蓝,类名就变成了谎言
  • .box 页面有十几个盒子,到底是哪一个?

命名是前端工程化中最被低估的难题。 BEM 规范正是为解决这个问题而生。


二、BEM 是什么?

BEMBlock(块)、Element(元素)、Modifier(修饰符) 的缩写,由俄罗斯搜索引擎 Yandex 提出,现已成为 CSS 命名的国际通用规范。

2.1 核心三要素

概念 说明 示例
Block(块) 独立的功能区块 .page .weui-btn
Element(元素) 块内部的组成部分 .page__hd .page__title
Modifier(修饰符) 块或元素的不同状态/变体 .weui-btn_primary .weui-btn_default

2.2 三种符号,各司其职

BEM 类名中会出现三种符号,经常被搞混,这里一次性说清楚:

符号 名称 作用 示例
- 连字符(hyphen) 同一个块/元素名内部单词之间的分隔 .weui-btn .button-sp-area
__ 双下划线(double underscore) Block 与 Element 之间的分隔 .page__hd .page__title
_ 下划线(underscore) Block/Element 与 Modifier 之间的分隔 .weui-btn_primary .weui-btn_default

别搞混-_ 长得像但作用完全不同------- 只是单词连接符(kebab-case),_ 才是 BEM 修饰符标记。拿 .weui-btn_primary 来说:weui-btn 里的 - 连接了 weuibtn 两个单词,_ 则标记了 primary 是修饰符。

2.3 命名公式

arduino 复制代码
.block {}                       /* 块 */
.block__element {}              /* 块__元素 */
.block_modifier {}              /* 块_修饰符 */
.block__element_modifier {}     /* 块__元素_修饰符 */

三、动手实践:一个 BEM 规范页面

下面通过一个真实案例来理解 BEM。我们要搭建一个微信风格的按钮展示页,完整代码如下:

3.1 HTML 结构

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>BEM 规范示例</title>
    <link rel="stylesheet" href="./common.css">
</head>
<body>
    <!-- BEM国际命名规范 -->
    <div class="page">
        <header class="page__hd">
            <h1 class="page__title">这是一个页面</h1>
            <p class="page__desc">这是一个页面的描述</p>
        </header>
        <main class="page__bd">
            <div class="button-sp-area">
                <a href="" class="weui-btn weui-btn_primary">主要按钮</a>
            </div>
            <div class="button-sp-area">
                <a href="" class="weui-btn weui-btn_default">默认按钮</a>
            </div>
        </main>
    </div>
</body>
</html>

3.2 结构拆解

dart 复制代码
.page                     ← Block:整个页面容器
├── .page__hd             ← Element:页面头部
│   ├── .page__title      ← Element:页面标题
│   └── .page__desc       ← Element:页面描述
└── .page__bd             ← Element:页面主体
    └── .button-sp-area   ← 独立区块:按钮展示区
        ├── .weui-btn .weui-btn_primary   ← Block + Modifier:主要按钮
        └── .weui-btn .weui-btn_default   ← Block + Modifier:默认按钮

一眼就能看出层级关系page 是最大的块,hdbd 是它的元素,titledesc 是头部下的子元素。不需要翻 HTML 结构,光看 CSS 类名就能脑补出 DOM 树。


四、CSS 实现详解

4.1 页面布局样式

css 复制代码
/* 页面底色与全屏 */
html, body {
    height: 100vh;
    background-color: #ededed;
}

/* Block: page --- 全屏定位容器 */
.page {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
}

/* Element: page__hd --- 头部区域 */
.page__hd {
    padding: 40px;
}

/* Element: page__title --- 标题 */
.page__title {
    text-align: left;
    font-size: 20px;
    font-weight: 400;
}

/* Element: page__desc --- 描述文字 */
.page__desc {
    margin-top: 4px;
    color: rgba(0, 0, 0, 0.45);
    text-align: left;
    font-size: 14px;
}

4.2 按钮组件样式(微信风格 weui)

css 复制代码
/* 按钮展示区域 */
.button-sp-area {
    text-align: center;
    margin: 15px auto;
    padding: 15px;
}

/* Block: weui-btn --- 按钮基类 */
.weui-btn {
    position: relative;
    display: block;
    min-width: 184px;
    max-width: 280px;
    margin-left: auto;
    margin-right: auto;
    padding: 12px 24px;
    font-weight: 500;
    font-size: 17px;
    text-align: center;
    text-decoration: none;
    color: #fff;
    line-height: 1.41176471; /* 24/17 设计师标注的行高比 */
    border-radius: 8px;
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
    user-select: none;
}

/* Modifier: 主要按钮(绿色) */
.weui-btn_primary {
    background-color: #07c160;
}

/* Modifier: 默认按钮(灰色) */
.weui-btn_default {
    color: rgba(0, 0, 0, 0.9);
    background-color: rgba(0, 0, 0, 0.1);
}

/* 相邻兄弟选择器:两个按钮之间的间距 */
.weui-btn + .weui-btn {
    margin-top: 15px;
}

4.3 关键设计细节

为什么 line-height: 1.41176471

这是从设计稿精确还原的结果。设计师标注:

  • 字体大小 font-size: 17px
  • 按钮高度 24px
  • 行高比例 = 24 ÷ 17 = 1.41176471...(取八位小数,四舍五入)

工程化思维:UI 还原不是"差不多就行",而是像素级精准。

-webkit-tap-highlight-color 的作用

css 复制代码
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);

消除移动端点击时默认的高亮背景色,让按钮交互更干净。

user-select: none

css 复制代码
user-select: none;

防止用户快速点击时意外选中按钮文字,提升移动端体验。


五、CSS Reset:把页面变成一张白纸

不同浏览器对 HTML 元素的默认样式各不相同(比如 h1 在不同浏览器下 margin 大小不一样)。CSS Reset 的作用就是抹平这些差异,让我们在一张"白纸"上作画。

5.1 为什么不用 * 通配符?

css 复制代码
/*  不推荐:性能差 */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

* 通配符会匹配页面中的每一个 元素,包括那些不需要重置的,造成不必要的性能开销。正确的做法是显式列出需要重置的元素

5.2 国际规范的 CSS Reset

css 复制代码
/* 无 * 通配符 | 显式列举的 CSS Reset */
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
    margin: 0;
    padding: 0;
    border: 0;
    font-size: 100%;
    font: inherit;
    vertical-align: baseline;
    box-sizing: border-box;
}

5.3 补充重置规则

css 复制代码
/* HTML5 块级元素兼容 --- 让老浏览器正确识别新标签 */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
    display: block;
}

/* 基础设置 */
body {
    line-height: 1;
    min-height: 100vh;
}

/* 去掉列表默认圆点 */
ol, ul {
    list-style: none;
}

/* 清除引用符号 */
blockquote, q {
    quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
    content: '';
    content: none;
}

/* 表格边框合并 */
table {
    border-collapse: collapse;
    border-spacing: 0;
}

/* 链接去掉下划线 */
a {
    text-decoration: none;
    color: inherit;
}

/* 表单元素统一样式 */
button, input, select, textarea {
    font: inherit;
    background: transparent;
    border: none;
    outline: none;
}

/* 媒体元素响应式 */
img, svg, picture, video {
    max-width: 100%;
    display: block;
}

/* 文本域仅允许垂直缩放 */
textarea {
    resize: vertical;
}

六、BEM 的四大优势

6.1 国际规范,团队协作零成本

BEM 是国际通用的命名规范。新成员加入团队,不需要学习你自创的命名体系------全球前端开发者都看得懂。

6.2 结构清晰,盒模型搭建方便

写页面本质上是"搭盒子":

  • 有一个区块要表达 → Block
  • 区块里有几个组成部分 → Element
  • 某个部分有不同状态 → Modifier

BEM 把这件事变得像搭积木一样直观。

6.3 简单易读,类名即文档

css 复制代码
/* 没有 BEM:需要猜这三个 class 的关系 */
.title { }
.desc { }
.hd { }

/* 有了 BEM:看类名就知道层级 */
.page__title { }
.page__desc { }
.page__hd { }

6.4 解决了"命名难"这一千古难题

没学 BEM 之前,给三个相关元素命名你需要绞尽脑汁想三个不同的单词。学了 BEM 之后:

markdown 复制代码
.page               → 1 个单词
.page__hd           → 复用 page,加 __hd
.page__title        → 复用 page,加 __title

用最简单的英文单词,跟页面结构一一对应。 不需要造词,不需要查词典。


七、BEM + 语义化标签 = 最佳实践

注意我们在 HTML 中同时使用了 语义化标签

html 复制代码
<header class="page__hd">   <!-- ✅ 语义化标签 表明这是头部 -->
    <h1 class="page__title">  <!-- ✅ h1 是页面主标题 -->
    <p class="page__desc">    <!-- ✅ p 是段落文本 -->
</header>
<main class="page__bd">     <!-- ✅ main 是页面主体 -->
标签 语义 为什么用它
<header> 头部区域 SEO 友好,屏幕阅读器可识别
<main> 主体内容 页面唯一核心内容区
<h1> 一级标题 告诉搜索引擎页面核心主题
<p> 段落 文本语义正确

BEM 管 CSS 命名,语义化标签管 HTML 结构。两者结合,才是真正的前端工程化。


八、总结

本文通过一个微信风格按钮页面的完整实现,覆盖了前端工程化的三个基石:

层次 技术 解决的问题
HTML 语义化标签 结构清晰、SEO 友好、无障碍访问
CSS 命名 BEM 国际规范 命名有章可循、层级一目了然
CSS 基础 CSS Reset 抹平浏览器差异、统一基准样式

这三者组合起来,就是你从"切图仔"走向"前端工程师"的第一步。


九、完整代码参考

以下代码已在实际项目中验证通过,可直接用于生产环境。

index.html

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>BEM 规范示例</title>
    <link rel="stylesheet" href="./common.css">
</head>
<body>
    <div class="page">
        <header class="page__hd">
            <h1 class="page__title">这是一个页面</h1>
            <p class="page__desc">这是一个页面的描述</p>
        </header>
        <main class="page__bd">
            <div class="button-sp-area">
                <a href="" class="weui-btn weui-btn_primary">主要按钮</a>
            </div>
            <div class="button-sp-area">
                <a href="" class="weui-btn weui-btn_default">默认按钮</a>
            </div>
        </main>
    </div>
</body>
</html>

common.css

css 复制代码
/* 
   CSS Reset --- 无 * 通配符,显式列举
   将浏览器默认样式统一归零
 */
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
    margin: 0;
    padding: 0;
    border: 0;
    font-size: 100%;
    font: inherit;
    vertical-align: baseline;
    box-sizing: border-box;
}

article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
    display: block;
}

body { line-height: 1; min-height: 100vh; }
ol, ul { list-style: none; }
blockquote, q { quotes: none; }
blockquote:before, blockquote:after,
q:before, q:after { content: ''; content: none; }
table { border-collapse: collapse; border-spacing: 0; }
a { text-decoration: none; color: inherit; }
button, input, select, textarea {
    font: inherit; background: transparent;
    border: none; outline: none;
}
img, svg, picture, video { max-width: 100%; display: block; }
textarea { resize: vertical; }

/* ========================================
   页面样式 --- BEM 命名规范
   ======================================== */
html, body { height: 100vh; background-color: #ededed; }

/* Block: page */
.page {
    position: absolute;
    top: 0; left: 0; right: 0; bottom: 0;
}

/* Element: page__hd */
.page__hd { padding: 40px; }

/* Element: page__title */
.page__title {
    text-align: left;
    font-size: 20px;
    font-weight: 400;
}

/* Element: page__desc */
.page__desc {
    margin-top: 4px;
    color: rgba(0, 0, 0, 0.45);
    text-align: left;
    font-size: 14px;
}

/* 按钮展示区 */
.button-sp-area {
    text-align: center;
    margin: 15px auto;
    padding: 15px;
}

/* Block: weui-btn --- 按钮基类 */
.weui-btn {
    position: relative;
    display: block;
    min-width: 184px;
    max-width: 280px;
    margin-left: auto;
    margin-right: auto;
    padding: 12px 24px;
    font-weight: 500;
    font-size: 17px;
    text-align: center;
    text-decoration: none;
    color: #fff;
    line-height: 1.41176471;
    border-radius: 8px;
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
    user-select: none;
}

/* Modifier: weui-btn_primary */
.weui-btn_primary { background-color: #07c160; }

/* Modifier: weui-btn_default */
.weui-btn_default {
    color: rgba(0, 0, 0, 0.9);
    background-color: rgba(0, 0, 0, 0.1);
}

/* 相邻兄弟选择器 */
.weui-btn + .weui-btn { margin-top: 15px; }

写在最后:BEM 不是什么高深的理论,它只是一套"把话说清楚"的命名约定。但它能让你和你的团队在 CSS 的世界里不再迷路。从今天开始,试试用 BEM 写你的下一个页面吧!


相关推荐
kyriewen1 小时前
开源|Image Harvest v1.0.5:AI 智能标签 + Eagle 导出,设计师和开发者的图片工作流神器
前端·javascript·ai编程
wuhen_n1 小时前
LangChain Memory 详解:实现 AI 连续对话不丢失上下文
前端·langchain·ai编程
wuhen_n1 小时前
LangChain Function Call 实战:让 AI 调用自定义工具
前端·langchain·ai编程
DyLatte1 小时前
很多人把坚持,误以为成长
前端·后端·程序员
yingyima2 小时前
凌晨3点的警报声:定时任务监控与告警的最佳实践
前端
zach2 小时前
React中的兄弟通讯之发布订阅模式
前端·react.js
书中枫叶2 小时前
我用 Vue3 写了一个 Chrome 步骤录制插件:自动截图、本地存储、一键导出教程
前端·vue.js
达达尼昂2 小时前
AI Native 工程实践 : agent 自动化测试
前端·后端·架构
2501_940041742 小时前
前端工程化命题,覆盖性能/架构/交互
前端·交互