前言:前端新手最容易忽略的两件事
刚学前端的时候,我的关注点全在"怎么把效果做出来"——调 margin、改颜色、加动画,折腾半天页面终于像样了。但回头一看代码,class 名起得乱七八糟:.box1、.title2、.red-btn……CSS 文件更是一团浆糊,这个元素多 8px,那个元素少 4px,全是"打补丁"修出来的。
后来我发现,真正让代码能维护的,不是你会多少花活,而是你是否遵循了一套命名规范和样式策略。写一个页面容易,维护一个项目难。而 BEM 命名规范和 CSS Reset,恰恰是前端工程化的第一课。
本文以我最近练手的一个仿微信 UI 页面为例,把这两件事掰开揉碎讲清楚。
📌 适合人群:刚入门 HTML/CSS,想知道怎么"写规范代码"的前端新人。
📌 你将收获:BEM 命名规范的理解与实操、CSS Reset 的完整方案、HTML5 语义化标签的实战用法、微信 UI 细节的还原思路。
一、先看成品:我们要做个什么?
一个简单的微信风格页面——标题区 + 描述区 + 两个按钮:
<div class="page">
<header class="page__hd">
<h1 class="page__title">这是一个页面</h1>
<p class="page__desc">这是一个页面的描述</p>
</header>
<main class="page__bd">
<a href="#" class="weui-btn weui-btn_primary">主要按钮</a>
<a href="#" class="weui-btn weui-btn_default">次要按钮</a>
</main>
</div>
页面结构极其简单,但其中藏着三个我刻意练习的核心点:
| 核心点 | 对应代码 | 为什么要练 |
|---|---|---|
| HTML5 语义化 | <header>、<main>、<h1> | 告别 <div> 套 <div>,让结构自带含义 |
| BEM 命名规范 | .page、.page__hd、.weui-btn_primary | 统一命名方式,代码自注释,协作友好 |
| CSS Reset | 50+ 行重置代码 | 消灭浏览器默认样式,让页面在所有浏览器表现一致 |
接下来逐个展开。
二、CSS Reset:在做任何样式之前,先把纸擦干净
2.1 为什么要 Reset?
不同浏览器对同一个 HTML 元素有自己内置的默认样式。比如:
- Chrome 给
<body>加了 8px 的margin - 不同浏览器对
<h1>的font-size默认值不一样 <ul>前面默认有小圆点,各个浏览器的缩进量不同
如果不做 Reset,你的页面在 Chrome 里好好的,到 Safari 里可能就歪了。CSS Reset 的目的,就是把这些浏览器自带的不一致样式全部干掉,给你一张"白纸"。
2.2 为什么不用 * 通配符?
很多教程上来就教你写:
/* ❌ 不推荐 */
* {
margin: 0;
padding: 0;
}
这个方法简单粗暴,但有两个问题:
- 性能差:
*是通配符选择器,浏览器需要匹配页面上的每一个元素(包括伪元素),渲染开销大 - 粒度太粗:一刀切地把所有元素的 margin/padding 都清零,有些你不想重置的也被重置了(比如你可能希望
<input>保留一些默认样式)
正确的做法是——显式列出所有需要重置的 HTML 元素:
/* ✅ 国际规范 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;
}
这段代码看起来很长,但它来自经典的 normalize.css 思路,覆盖了几乎所有的 HTML 标签。每一行做了什么:
| 属性 | 作用 |
|---|---|
margin: 0 padding: 0 | 清空内外边距 |
border: 0 | 去掉默认边框(如 <fieldset>) |
font-size: 100% | 统一字体大小为父元素的 100% |
font: inherit | 强制继承父元素字体 |
vertical-align: baseline | 统一垂直对齐方式 |
box-sizing: border-box | 关键! 让 width/height 包含 padding 和 border,布局计算更直觉 |
🔑
box-sizing: border-box可能是你学到的最有用的一行 CSS。没有它,你设
width: 200px; padding: 20px,元素实际宽度是200 + 20 + 20 = 240px。有了它,元素宽度就是200px,padding 从里面扣。这个行为更符合直觉,建议全局设置。
2.3 HTML5 块级元素兼容
HTML5 引入了 <article>、<section>、<header>、<footer> 等语义化标签,但老版本 IE 不认识它们,会默认把它们当行内元素渲染。所以需要显式声明:
/* HTML5 块级元素兼容 */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
2.4 其他重置细节
body {
line-height: 1; /* 重置行高,避免继承到奇怪的值 */
min-height: 100vh; /* 确保 body 至少撑满一屏 */
}
ol, ul {
list-style: none; /* 去掉列表前的小圆点 */
}
blockquote, q {
quotes: none; /* 去掉引号的默认样式 */
}
table {
border-collapse: collapse; /* 合并单元格边框,不合并会有间隙 */
border-spacing: 0;
}
a {
text-decoration: none; /* 去掉链接下划线 */
color: inherit; /* 链接颜色跟随父元素 */
}
img, svg, picture, video {
max-width: 100%; /* 图片不超出容器 */
display: block; /* 消除图片底部的 3px 间隙 */
}
💡 每个属性都有它存在的理由,不是复制粘贴就完事。 比如
img { display: block }这行——<img>默认是行内元素,会被 baseline 对齐影响,导致图片底部多出 3px 的神秘空白。改成block就解决了。这些细节,自己踩过坑才会记住。
三、BEM 命名规范:解决前端界的"起名难"问题
3.1 命名混乱是前端最大的技术债
你有没有写过这样的 class:
.red-button { } /* 后来按钮改成绿色了,名字还是 red */
.title1 { } /* title2、title3 各是什么意思? */
.mainBox { } /* 到底是驼峰还是下划线? */
.section_content { } /* 这跟 .section__content 有什么区别? */
这些问题的根源都一样:没有统一的命名规则。 每个人按自己的习惯来,三个月后自己都看不懂。
BEM 就是来解决这个问题的。
3.2 BEM 是什么?
BEM = Block(块)、Element(元素)、Modifier(修饰符),三个概念组成一套命名规则:
block__element--modifier
│ │ │
│ │ └─ 修饰符:表示元素的不同状态或变体
│ └────────── 元素:块内部的组成部分
└────────────────── 块:一个独立的、有意义的组件
连接符规则:
- Block 和 Element 之间用
__(双下划线) - Block/Element 和 Modifier 之间用
_(单下划线)
看一个真实例子就全明白了:
/* Block:一个页面区块 */
.page { }
/* Element:页面区块里的头部 */
.page__hd { }
.page__title { }
.page__desc { }
.page__bd { }
/* Block:一个按钮组件(weui 框架中的按钮) */
.weui-btn { }
/* Modifier:按钮的不同状态 */
.weui-btn_primary { } /* 主要按钮(绿色) */
.weui-btn_default { } /* 默认按钮(灰色) */
对应的 HTML:
<div class="page"> <!-- Block -->
<header class="page__hd"> <!-- Element -->
<h1 class="page__title">标题</h1> <!-- Element -->
</header>
<main class="page__bd"> <!-- Element -->
<a class="weui-btn weui-btn_primary">主要</a> <!-- Block + Modifier -->
</main>
</div>
3.3 为什么 BEM 值得学?
第一,解决了"起名难"。 BEM 把命名变成填空题——你只需要回答三个问题:
- 这是什么组件?(Block 名)
- 这是组件里的哪个部分?(Element 名)
- 它现在是哪种状态?(Modifier 名)
比如微信的按钮组件,不用纠结叫 .greenBtn 还是 .mainBtn,BEM 直接规定:
- 所有按钮都叫
.weui-btn - 主要按钮叫
.weui-btn_primary - 默认按钮叫
.weui-btn_default
第二,结构即文档。 任何人看到 .page__hd__title(虽然严格来说 BEM 不建议三级嵌套,但思路一样),立刻知道这个元素的层级关系:它是 page 块下 hd 区域里的 title。
第三,避免样式冲突。 所有 class 都是唯一的,不会出现 .title 被页面里三个不同组件同时用的情况。
🧠 我的理解:BEM 本质上是一种命名约定,不是框架、不是库。它的核心思想是——用名字表达结构和含义,而不是用名字描述样式。
.red-text是描述样式(坏了,以后改成蓝色怎么办),.page__error是表达含义。
四、实战:仿微信 UI 页面的完整拆解
4.1 页面布局:绝对定位 vs Flexbox
这个页面的布局用了 position: absolute 实现全屏铺满:
.page {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
/* 四边拉满 = 全屏 */
}
top: 0; left: 0; right: 0; bottom: 0 四边同时设为 0,效果等价于 width: 100vw; height: 100vh,但兼容性更好。
💡 一个调试小技巧:写布局的时候,给区块加个临时背景色,一眼就能看出它占据了多大空间。我在学习时管这叫"背景调试大法":
.page { /* background-color: rgba(255, 0, 0, 0.1); 调试完删掉 */ }
4.2 头部区域:标题和描述的层级关系
.page__hd {
padding: 40px; /* 微信页面惯用的大间距 */
}
.page__title {
text-align: left; /* 虽然默认就是 left,但显式写出来是意图声明 */
font-size: 20px; /* 比浏览器默认的 16px 大一圈 */
font-weight: 400; /* 正常粗细,不加粗 */
}
.page__desc {
margin-top: 4px;
color: rgba(0, 0, 0, 0.45); /* 次要文字用灰色,弱化视觉权重 */
text-align: left;
font-size: 14px;
}
这里有三个设计细节值得注意:
font-weight: 400:很多同学会直接写bold或700,但微信的设计语言偏轻盈,标题也不加粗color: rgba(0, 0, 0, 0.45):灰色文字不要用#ccc或#999,用rgba控制透明度,这样在不同背景上表现更一致margin-top: 4px:描述和标题之间的间距很小(4px),这是微信 UI 的紧凑设计风格
4.3 按钮组件:微信设计规范的精髓
按钮是整个页面最核心的视觉元素,也是最有技术含量的部分:
.weui-btn {
position: relative; /* 为可能的绝对定位子元素提供锚点 */
display: block; /* 块级元素,独占一行 */
min-width: 184px; /* 最小宽度,保证按钮不会太窄 */
max-width: 280px; /* 最大宽度,保证按钮不会太宽 */
margin-left: auto; /* 水平居中的另一种写法 */
margin-right: auto; /* 配合 margin-left: auto 实现居中 */
padding: 12px 24px; /* 上下 12px,左右 24px */
font-weight: 500; /* 中等粗细 */
font-size: 17px; /* ⭐ 微信特色的字体大小 */
color: #fff;
line-height: 1.41176471; /* ⭐ 这个数字怎么来的?见下方 */
border-radius: 8px; /* 圆角 */
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); /* 去掉移动端点击高亮 */
user-select: none; /* 文字不可选中,更像原生按钮 */
}
🔑
line-height: 1.41176471是怎么算出来的?这是 UI 设计师标注决定的:按钮文字
font-size: 17px,按钮高度应该是24px。所以:line-height = 按钮高度 / 字号 = 24 / 17 = 1.411764705882353这个数字不是随便写的——它是从设计稿精确还原出来的。专业的前端开发,就是要能把设计师的标注精准地翻译成 CSS。
/* 主要按钮:微信绿 */
.weui-btn_primary {
background-color: #07c160; /* 微信的品牌绿色 */
}
/* 默认按钮:灰色半透明 */
.weui-btn_default {
color: rgba(0, 0, 0, 0.9);
background-color: rgba(0, 0, 0, 0.25);
}
4.4 相邻按钮之间的间距
/* 相邻兄弟选择器:选择紧跟在另一个 .weui-btn 后面的 .weui-btn */
.weui-btn + .weui-btn {
margin-top: 12px;
}
这里用了一个很巧妙的选择器——相邻兄弟选择器 +。它的含义是:选择紧跟在另一个 .weui-btn 后面 的 .weui-btn。
效果是:
- 第一个按钮没有
margin-top(因为它前面没有兄弟.weui-btn) - 第二个、第三个按钮各有
12px的margin-top
这样就实现了"按钮之间有间距,但第一个按钮不往下偏移"的效果——不需要额外加 class,不需要
:first-child,优雅。
五、HTML5 语义化标签:HTML 不只是 <div>
5.1 <div> 不是万能标签
很多新手(包括以前的我)写 HTML 只有一个套路:
<div class="header"> <!-- 用 div 表示头部 -->
<div class="main"> <!-- 用 div 表示主体 -->
<div class="footer"> <!-- 用 div 表示底部 -->
能跑,但不够好。HTML5 提供了 语义化标签,让每个标签自带含义:
| 标签 | 含义 | 替代的写法 |
|---|---|---|
<header> | 页面或区块的头部 | <div class="header"> |
<main> | 页面的主要内容 | <div class="main"> |
<footer> | 页面或区块的底部 | <div class="footer"> |
<nav> | 导航链接组 | <div class="nav"> |
<article> | 独立的文章内容 | <div class="article"> |
<section> | 文档中的一个章节 | <div class="section"> |
<aside> | 侧边栏内容 | <div class="sidebar"> |
我们的页面就用了 <header> 和 <main>:
<header class="page__hd">
<h1 class="page__title">这是一个页面</h1>
</header>
<main class="page__bd">
<!-- 主体内容 -->
</main>
5.2 语义化标签好在哪?
第一,对搜索引擎友好(SEO)。 搜索引擎爬虫能理解 <main> 里的内容是页面核心,<header> 是头部导航。
第二,对屏幕阅读器友好(可访问性)。 视障用户使用的屏幕阅读器,会依据语义化标签来构建页面的导航结构,帮助他们快速跳转到核心内容。
第三,代码可读性。 看 <header> 就知道是头部,看 <main> 就知道是主体。语义化标签让 HTML 自注释。
六、我的学习反思:慢下来,把基础打牢
写完这个页面,我有几个很深的感受。
6.1 先写结构,再写样式
这是我从这次练习中学到的最重要的工程习惯——
❌ 错误姿势:边写 HTML 边写 CSS,写一点调一点,最后结构混乱
✅ 正确姿势:先完成 HTML 结构,确认语义正确,再统一写 CSS
就像一个房子,你得先搭好框架,再装修。边盖墙边刷漆,房子会塌的。
6.2 CSS Reset 不是复制粘贴
CSS Reset 的每一行都在解决一个具体问题。写的时候思考"这一行在重置什么",而不是把网上的代码原封不动粘过来。
举个例子:img { display: block } 是为了消除图片底部的 3px 间隙。如果你不知道为什么,你可能在遇到"图片下面多了一条缝"的时候,以为是 margin 的问题,然后加了 margin-bottom: -3px——这就叫"打补丁"。补丁会越打越多,代码会越来越难维护。
6.3 BEM 让命名不再是负担
命名曾经是我写 CSS 最头疼的事。有了 BEM 之后,命名变成了"填空题"——看到什么就写什么。.page__title 就是"页面里的标题",不需要绞尽脑汁想一个"独特的名字"。
6.4 关注 UI 设计细节
以前我写 CSS,间距都是"凭感觉"——觉得差不多就写 margin-top: 10px。但真正的 UI 还原,是要像这样算的:
line-height = 设计稿标注的按钮高度 / 设计稿标注的字号
= 24px / 17px
= 1.41176471
像素级的还原,来自像素级的严谨。
七、总结
graph TD
A[HTML5 语义化标签] --> D[干净的页面结构]
B[CSS Reset 重置样式] --> D
C[BEM 命名规范] --> D
D --> E[可维护的前端代码]
E --> F[团队协作友好]
E --> G[自己三个月后还看得懂]
这三个东西都不是什么高深的技术——CSS Reset 是写了几十年的老知识,BEM 命名出来快十年了,HTML5 标签也是 2014 年的标准。但它们合在一起,构成了前端工程化的第一块基石。
技术栈会变(今天 jQuery,明天 React,后天不知道什么),但这些基础规范不会变。花一个下午把 BEM 和 CSS Reset 吃透,比追新框架值。