为什么不能全用 div?HTML 语义化的真正价值
前言
上一篇我们搞清楚了浏览器和服务器的”对话”方式。现在问题来了:服务器返回的那一大段 HTML 文本,到底该怎么写?
HTML(HyperText Markup Language,超文本标记语言) 不是编程语言,而是一种标记语言——用标签(tag)来描述内容的结构和含义。如果你有 C 语言基础,可以这样理解:C 语言告诉计算机”怎么做”,HTML 告诉浏览器”这是什么”。
刚开始学 HTML 时,很多人(包括我)会觉得:反正 <div> 能装一切,为什么要记那么多标签?这篇文章会回答这个问题,同时带你掌握 HTML 的文档结构和最常用的标签。
正文
1. HTML 文档的基本骨架
每个 HTML 文件都遵循相同的基本结构:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>页面标题</title>
</head>
<body>
<!-- 页面的可见内容放在这里 -->
</body>
</html>
逐行解释:
| 代码 | 作用 |
|---|---|
<!DOCTYPE html> | 声明文档类型为 HTML5,告诉浏览器用最新标准解析 |
<html lang="zh-CN"> | 根元素,lang 属性指定页面语言(影响搜索引擎和屏幕阅读器) |
<head> | 头部区域,存放元数据(不直接显示在页面上) |
<meta charset="UTF-8"> | 字符编码,UTF-8 支持中文和各种特殊字符 |
<meta name="viewport" ...> | 视口设置,确保在手机上正确显示 |
<title> | 页面标题,显示在浏览器标签页上 |
<body> | 主体区域,所有可见内容都在这里 |
用 C 语言的思路理解:<head> 相当于文件顶部的 #include 和宏定义(声明但不直接显示),<body> 相当于 main() 函数(用户真正看到的内容)。
2. 标签的基本语法
HTML 标签的通用格式:
<标签名 属性名="属性值">内容</标签名>
两种标签类型:
<!-- 双标签(有开始和结束) -->
<p>这是一个段落</p>
<a href="https://example.com">这是一个链接</a>
<!-- 单标签(自闭合,没有内容) -->
<img src="photo.jpg" alt="照片描述">
<br>
<hr>
<input type="text">
标签可以嵌套,形成树形结构(这就是 DOM 树的由来):
<div>
<h1>标题</h1>
<p>这是一段文字,包含一个<a href="#">链接</a>。</p>
</div>
对应的树形结构:
div
├── h1
│ └── "标题"
└── p
├── "这是一段文字,包含一个"
├── a
│ └── "链接"
└── "。"
💡 工程师手记:HTML 的嵌套结构让我想起 Verilog 中模块的层次化实例化——顶层模块包含子模块,子模块还能再包含更小的模块。DOM 树就是 HTML 标签的”层次化结构图”,后续学 JavaScript 时你会频繁和它打交道。
(建议替换为你自己第一次理解 DOM 树时的感受)
3. 常用 HTML 标签速查
HTML 标签有上百个,但日常开发中常用的也就二十几个。下面按类别快速过一遍,不需要记住所有细节——用到的时候查文档就行,重要的是知道有哪些”工具”可用。
3.1 文本内容标签
<!-- 标题:h1 最大最重要,h6 最小,一个页面通常只有一个 h1 -->
<h1>一级标题</h1>
<h2>二级标题</h2>
<h3>三级标题</h3>
<!-- 段落 -->
<p>这是一个段落。段落之间会自动产生间距。</p>
<!-- 强调 -->
<strong>加粗强调(语义:重要)</strong>
<em>斜体强调(语义:着重)</em>
<!-- 换行和分隔线 -->
<br> <!-- 换行 -->
<hr> <!-- 水平分隔线 -->
<!-- 预格式化文本(保留空格和换行,常用于代码展示) -->
<pre>
int main() {
return 0;
}
</pre>
<!-- 行内代码 -->
<code>printf("hello")</code>
3.2 链接与图片
<!-- 超链接 -->
<a href="https://www.baidu.com">访问百度</a>
<a href="https://example.com" target="_blank">在新标签页打开</a>
<a href="#section2">跳转到页面内的 section2(锚点链接)</a>
<a href="mailto:[email protected]">发送邮件</a>
<!-- 图片 -->
<img src="images/photo.jpg" alt="这张图片的文字描述" width="300">
<!--
src:图片路径(可以是相对路径或 URL)
alt:替代文本(图片加载失败时显示,也用于无障碍访问)
width/height:尺寸(建议只设一个,另一个自动等比缩放)
-->
3.3 列表
<!-- 无序列表(圆点) -->
<ul>
<li>HTML</li>
<li>CSS</li>
<li>JavaScript</li>
</ul>
<!-- 有序列表(数字) -->
<ol>
<li>第一步:安装编辑器</li>
<li>第二步:创建文件</li>
<li>第三步:编写代码</li>
</ol>
<!-- 定义列表(术语 + 解释) -->
<dl>
<dt>HTML</dt>
<dd>超文本标记语言,用于定义网页结构</dd>
<dt>CSS</dt>
<dd>层叠样式表,用于控制网页样式</dd>
</dl>
3.4 表格
<table>
<thead>
<tr>
<th>姓名</th>
<th>年龄</th>
<th>职业</th>
</tr>
</thead>
<tbody>
<tr>
<td>张三</td>
<td>28</td>
<td>工程师</td>
</tr>
<tr>
<td>李四</td>
<td>25</td>
<td>设计师</td>
</tr>
</tbody>
</table>
<thead>表头、<tbody>表体、<th>表头单元格、<td>普通单元格、<tr>表格行。
3.5 表单元素
<form action="/submit" method="POST">
<!-- 文本输入 -->
<label for="username">用户名:</label>
<input type="text" id="username" name="username" placeholder="请输入用户名">
<!-- 密码输入 -->
<label for="password">密码:</label>
<input type="password" id="password" name="password">
<!-- 邮箱(自带格式验证) -->
<input type="email" name="email" placeholder="[email protected]">
<!-- 数字 -->
<input type="number" name="age" min="0" max="150">
<!-- 下拉选择 -->
<select name="city">
<option value="beijing">北京</option>
<option value="shanghai">上海</option>
<option value="shenzhen">深圳</option>
</select>
<!-- 多行文本 -->
<textarea name="bio" rows="4" cols="50" placeholder="自我介绍"></textarea>
<!-- 复选框 -->
<input type="checkbox" id="agree" name="agree">
<label for="agree">我同意用户协议</label>
<!-- 单选按钮 -->
<input type="radio" name="gender" value="male"> 男
<input type="radio" name="gender" value="female"> 女
<!-- 提交按钮 -->
<button type="submit">提交</button>
</form>
关键概念:
<label>的for属性要与对应<input>的id匹配,这样点击标签文字也能聚焦到输入框(提升用户体验和无障碍访问)。
4. 容器标签:div 与 span
<!-- div:块级容器,独占一行,用于组合多个元素 -->
<div>
<h2>文章标题</h2>
<p>文章内容...</p>
</div>
<!-- span:行内容器,不换行,用于包裹文本片段 -->
<p>价格:<span style="color: red;">¥99</span> 元</p>
<div> 和 <span> 本身没有语义含义,它们是”通用容器”——什么都能装,但不告诉浏览器”装的是什么”。
在 HTML5 之前,页面布局几乎全靠 <div> 嵌套,这就是所谓的 “div 汤”(div soup)。
💡 工程师手记:我写的第一个 HTML 页面就是典型的 div 汤——一个
<div>套另一个<div>,嵌套了七八层。三天后回来改 bug,看着满屏的</div>完全分不清哪个对应哪个。那时候我就想:有没有更有意义的标签名?(建议替换为你自己第一次写 HTML 时的真实经历)
5. ★ 从 div 汤到语义化:HTML5 语义标签
这是本文的核心内容。先看一个对比——同一个页面结构,两种写法:
div 汤写法(HTML5 之前的主流做法):
<div class="header">
<div class="nav">...</div>
</div>
<div class="main">
<div class="article">
<div class="section">...</div>
</div>
<div class="sidebar">...</div>
</div>
<div class="footer">...</div>
语义化写法(HTML5 推荐):
<header>
<nav>...</nav>
</header>
<main>
<article>
<section>...</section>
</article>
<aside>...</aside>
</main>
<footer>...</footer>
两种写法在浏览器里显示效果完全一样。那为什么要用语义标签?
语义化的四重价值
- 可读性:代码一目了然。看到
<nav>就知道是导航,看到<div class="nav">还得去查 CSS 确认 - 无障碍(Accessibility):屏幕阅读器会告诉视障用户”这是导航区域""这是主要内容”——用
<div>它什么都不知道 - SEO(搜索引擎优化):搜索引擎能通过
<article>和<main>识别页面的核心内容,给予更准确的排名 - 可维护性:团队协作时,语义标签就是天然的代码文档
💬 你可能会问:语义化听起来很好,但不用语义标签页面不也能正常显示吗?为什么要费这个劲?
确实,纯视觉层面没有区别。但 Web 的用户不只是”看得见的人用鼠标点击”——还有视障用户用屏幕阅读器、搜索引擎爬虫、各种自动化工具。语义标签是你和这些”非人类用户”沟通的唯一渠道。就像给代码写注释——不写也能跑,但维护起来是噩梦。
语义标签速查表
| 标签 | 语义 | 替代了什么 |
|---|---|---|
<header> | 页面或区域的头部 | <div class="header"> |
<nav> | 导航链接区域 | <div class="nav"> |
<main> | 页面主要内容(唯一) | <div class="main"> |
<article> | 独立的内容块(文章、帖子) | <div class="article"> |
<section> | 主题性的内容分组 | <div class="section"> |
<aside> | 侧边栏、附属信息 | <div class="sidebar"> |
<footer> | 页面或区域的底部 | <div class="footer"> |
<figure> | 图片/图表及其说明 | <div class="image-wrapper"> |
<figcaption> | <figure> 的标题 | <p class="caption"> |
💬 你可能会问:div 和 section 到底有什么区别?什么时候该用哪个?
简单判断:如果这块内容有一个明确的主题(能给它起个小标题),用
<section>;如果只是为了布局或样式把几个元素组合在一起,用<div>。<section>= “有主题的内容分组”,<div>= “无语义的通用容器”。
一个完整的语义化页面示例
<body>
<header>
<nav>
<a href="/">首页</a>
<a href="/blog">博客</a>
<a href="/about">关于</a>
</nav>
</header>
<main>
<article>
<h1>文章标题</h1>
<p>文章内容...</p>
<section>
<h2>第一节</h2>
<p>内容...</p>
</section>
<section>
<h2>第二节</h2>
<p>内容...</p>
</section>
</article>
<aside>
<h3>侧边栏</h3>
<p>相关推荐、广告等</p>
</aside>
</main>
<footer>
<p>© 2026 我的网站</p>
</footer>
</body>
6. 块级元素 vs 行内元素
HTML 元素分为两大显示类型,理解这个区别对后续学 CSS 很重要:
| 特性 | 块级元素(Block) | 行内元素(Inline) |
|---|---|---|
| 换行 | 独占一行 | 不换行,与其他行内元素同行 |
| 宽度 | 默认占满父容器宽度 | 由内容决定宽度 |
| 嵌套 | 可以包含块级和行内元素 | 通常只包含行内元素或文本 |
| 代表 | div, p, h1-h6, ul, ol, table, form | span, a, strong, em, img, input |
<!-- 块级元素:各占一行 -->
<p>第一段</p>
<p>第二段</p>
<!-- 行内元素:同一行显示 -->
<span>姓名</span>
<span>年龄</span>
<a href="#">链接</a>
💡 工程师手记:这个区分刚开始让我很困惑——为什么有的标签自动换行、有的不换行?后来发现关键在于:块级元素像”一整行货架”(不管放多少东西都独占一行),行内元素像”货架上的商品”(挨着排列)。下一篇学 CSS 的
display属性时,你会发现这个行为是可以改的。(建议替换为你自己理解块级/行内区别的过程)
7. 动手实践
创建一个 index.html 文件,搭建一个简单的个人介绍页面。注意:这次要用语义化标签,不要写 div 汤。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>关于我 - 前端学习者</title>
</head>
<body>
<header>
<nav>
<a href="#about">关于我</a> |
<a href="#skills">技能</a> |
<a href="#projects">项目</a>
</nav>
</header>
<main>
<section id="about">
<h1>你好,我是一名前端学习者</h1>
<p>我有 <strong>C 语言</strong>和<strong>嵌入式</strong>背景,正在学习前端开发。</p>
<img src="https://via.placeholder.com/200" alt="我的头像">
</section>
<section id="skills">
<h2>技能清单</h2>
<ul>
<li>C / Python</li>
<li>FPGA / Verilog</li>
<li>HTML / CSS(学习中)</li>
<li>JavaScript(即将学习)</li>
</ul>
</section>
<section id="projects">
<h2>项目经历</h2>
<table>
<thead>
<tr>
<th>项目</th>
<th>技术栈</th>
<th>状态</th>
</tr>
</thead>
<tbody>
<tr>
<td>串口收发器</td>
<td>Verilog</td>
<td>已完成</td>
</tr>
<tr>
<td>个人博客</td>
<td>Astro + React</td>
<td>进行中</td>
</tr>
</tbody>
</table>
</section>
</main>
<footer>
<hr>
<p>© 2026 前端学习笔记 | <a href="mailto:[email protected]">联系我</a></p>
</footer>
</body>
</html>
用浏览器打开这个文件,你会看到一个没有任何样式的”裸页面”——这就是纯 HTML 的样子。然后打开 DevTools 的 Elements 面板,展开 DOM 树,对照你写的标签看看结构是否和你预期一致。
常见问题
💬 你可能会问:HTML 标签这么多,我需要全部记住吗?
完全不需要。日常开发用到的标签不超过 20 个。记住文档骨架(html/head/body)、基础内容(h1-h6/p/a/img/ul/ol)、语义结构(header/nav/main/article/section/aside/footer)就足够了。其他的用到时查 MDN 文档 即可。
💬 你可能会问:表单那么多 input 类型,实际开发中最常用的是哪几个?
text、password、number这四个覆盖 80% 的场景。checkbox和radio也常用。其他类型(如date、range、color)根据需求再学。
总结
| 知识点 | 核心要点 |
|---|---|
| 文档骨架 | <!DOCTYPE html> + <html> + <head> + <body> |
| 常用标签 | 标题 h1-h6、段落 p、链接 a、图片 img、列表 ul/ol、表格 table、表单 form |
| 容器标签 | div(块级通用容器)、span(行内通用容器)——无语义 |
| 语义化标签 | header / nav / main / article / section / aside / footer |
| 语义化价值 | 可读性、无障碍访问、SEO、可维护性——不只是”显示”,更是”沟通” |
| 块级 vs 行内 | 块级独占一行,行内不换行(CSS 可以改变) |
下一步行动:用语义化标签重新搭建你的个人介绍页面,然后用 Chrome DevTools 的 Elements 面板检查 DOM 树结构。下一篇我们开始给这个”裸页面”穿上漂亮的衣服——CSS。
参考资料
📖 系列导航:本文是「FPGA 工程师的前端学习笔记」系列的第 2 篇 上一篇:从嵌入式到 Web:浏览器和服务器是怎么”对话”的 下一篇:CSS 入门:选择器与盒模型