写页面最怕什么?命名难、样式乱、维护痛。本文带你从零掌握 BEM 命名规范和 CSS Reset,让你的代码结构清晰、可维护性拉满。
一、为什么你的 CSS 总是一团糟?
刚入门前端时,我们通常会这样写 CSS:
css
.title { font-size: 20px; }
.red { color: red; }
.box { margin: 10px; }
看起来没什么问题,但当页面变复杂后:
.title是哪个区块的标题?.red今天红明天蓝,类名就变成了谎言.box页面有十几个盒子,到底是哪一个?
命名是前端工程化中最被低估的难题。 BEM 规范正是为解决这个问题而生。
二、BEM 是什么?
BEM 是 Block(块)、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里的-连接了weui和btn两个单词,_则标记了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是最大的块,hd和bd是它的元素,title和desc是头部下的子元素。不需要翻 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 写你的下一个页面吧!