HTML 空标签(Void Elements)
什么是空标签?
在 HTML 中,大多数标签都是成对出现的,有开始标签和结束标签,比如 <div></div>、<p></p>。但有一类特殊的标签没有结束标签、也不能包含任何子内容,它们就是空标签(Void Elements)。
<!-- 普通标签:成对出现,可以包含内容 -->
<p>这是一段文字</p>
<!-- 空标签:没有结束标签,不包含内容 -->
<br>
<img src="logo.png" alt="Logo">
<input type="text">
空标签在不同场景下有多种叫法:
- Void Elements(W3C / WHATWG 官方术语)
- 空标签 / 空元素(中文社区常用)
- 自闭合标签(Self-closing Tags,严格来说是 XHTML 的写法)
本文统一使用"空标签"来称呼。
为什么需要空标签?
空标签存在的核心原因是:它们表示的内容本身就不需要"包裹"子元素。
比如:
<img>本身就是一张图片,不需要在里面再放其他元素<br>就是一个换行,换行这个动作不需要"包裹"任何内容<input>是一个表单控件,内容由value属性控制,而不是子元素
完整的空标签列表
HTML5 规范中定义了以下空标签:
| 标签 | 用途 | 常用程度 |
|---|---|---|
<area> | 图像映射区域 | 较少 |
<base> | 文档基准 URL | 较少 |
<br> | 换行 | 高频 |
<col> | 表格列属性 | 一般 |
<embed> | 嵌入外部内容 | 一般 |
<hr> | 水平分割线 | 高频 |
<img> | 图片 | 高频 |
<input> | 表单输入控件 | 高频 |
<link> | 外部资源链接(CSS 等) | 高频 |
<meta> | 文档元信息 | 高频 |
<param> | 对象参数(已废弃) | 极少 |
<source> | 媒体资源 | 一般 |
<track> | 字幕轨道 | 较少 |
<wbr> | 可选换行点 | 较少 |
高频空标签可以用这句话记住:"BIL MIH S"
- Br, Img, Link
- Meta, Input, Hr
- Source
日常开发中,掌握这 7 个就覆盖了绝大多数场景。
逐个详解常用空标签
<br> — 换行
在文本中插入一个换行符。
<p>
第一行文字<br>
第二行文字<br>
第三行文字
</p>
注意事项:
- 不要用多个
<br>来制造间距,应该用 CSS 的margin或padding <br>适用于诗歌、地址等内容确实需要换行的场景
<!-- ❌ 错误用法:用 br 制造间距 -->
<p>标题</p>
<br><br><br>
<p>内容</p>
<!-- ✅ 正确用法:用 CSS 控制间距 -->
<p style="margin-bottom: 2rem;">标题</p>
<p>内容</p>
<img> — 图片
在页面中嵌入一张图片。
<img src="photo.jpg" alt="一张风景照" width="800" height="600">
关键属性:
| 属性 | 说明 | 是否必须 |
|---|---|---|
src | 图片路径 | 是 |
alt | 替代文本(图片加载失败或屏幕阅读器使用) | 是(语义必须) |
width | 宽度 | 建议设置(防止布局偏移) |
height | 高度 | 建议设置(防止布局偏移) |
loading | 懒加载,值为 lazy 或 eager | 可选 |
<!-- 响应式图片 + 懒加载 -->
<img
src="photo.jpg"
alt="风景照"
width="800"
height="600"
loading="lazy"
>
<input> — 表单输入
HTML 中最多变的空标签,通过 type 属性变成不同的表单控件。
<!-- 文本框 -->
<input type="text" placeholder="请输入用户名">
<!-- 密码框 -->
<input type="password" placeholder="请输入密码">
<!-- 复选框 -->
<input type="checkbox" id="agree">
<!-- 单选按钮 -->
<input type="radio" name="gender" value="male">
<!-- 文件上传 -->
<input type="file" accept="image/*">
<!-- 提交按钮 -->
<input type="submit" value="提交">
<input> 的 type 属性支持超过 20 种值,包括 text、password、email、number、date、color、range 等。
<hr> — 水平分割线
表示主题内容之间的分隔。
<h2>第一章</h2>
<p>第一章的内容...</p>
<hr>
<h2>第二章</h2>
<p>第二章的内容...</p>
<hr> 是有语义的,表示"话题转换",不仅仅是一条视觉线条。
<meta> — 文档元信息
在 <head> 中提供页面的元数据。
<head>
<!-- 字符编码 -->
<meta charset="UTF-8">
<!-- 响应式视口 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- 页面描述(SEO 重要) -->
<meta name="description" content="这是一个学习 HTML 空标签的教程">
<!-- Open Graph(社交分享) -->
<meta property="og:title" content="HTML 空标签详解">
</head>
<link> — 外部资源链接
在 <head> 中引入外部资源,最常见的是 CSS 样式表。
<head>
<!-- 引入 CSS -->
<link rel="stylesheet" href="styles.css">
<!-- 网站图标 -->
<link rel="icon" href="favicon.ico">
<!-- 预加载字体 -->
<link rel="preload" href="font.woff2" as="font" crossorigin>
</head>
<source> — 媒体资源
为 <video>、<audio> 或 <picture> 提供多个备选资源。
<!-- 视频多格式兼容 -->
<video controls>
<source src="movie.webm" type="video/webm">
<source src="movie.mp4" type="video/mp4">
您的浏览器不支持 video 标签。
</video>
<!-- 响应式图片 -->
<picture>
<source media="(min-width: 800px)" srcset="large.jpg">
<source media="(min-width: 400px)" srcset="medium.jpg">
<img src="small.jpg" alt="响应式图片">
</picture>
空标签的写法:<br> vs <br/> vs <br />
这是前端开发中经常引起困惑的问题。我们来理清三种写法的背景:
| 写法 | 在 HTML5 中是否合法 | 说明 |
|---|---|---|
<br> | 合法 | HTML5 推荐写法 |
<br/> | 合法 | 兼容写法 |
<br /> | 合法 | XHTML 风格,斜杠前有空格 |
<br></br> | 不合法 | 空标签不允许有结束标签 |
在 HTML5 中,空标签不允许写结束标签。以下写法是错误的:
<!-- ❌ 错误!空标签不能有结束标签 -->
<br></br>
<img src="a.png"></img>
<input type="text"></input>
浏览器虽然不会报错(容错机制),但这不符合规范,可能导致意想不到的解析问题。
各框架中的惯例
| 环境 | 推荐写法 | 原因 |
|---|---|---|
| 纯 HTML5 | <br> | 规范推荐,最简洁 |
| React / JSX | <br /> | JSX 要求所有标签必须闭合 |
| Vue 模板 | <br> 或 <br /> | 两者均可 |
| XHTML | <br /> | XML 语法要求 |
空标签 vs 空内容标签
空标签和"内容为空的普通标签"是两个不同的概念,不要混淆。
<!-- 空标签(Void Element):规范规定不能有子内容 -->
<br>
<img src="a.png" alt="">
<!-- 空内容标签:普通标签,只是碰巧没写内容 -->
<div></div>
<p></p>
<span></span>
关键区别:
| 对比项 | 空标签(Void Element) | 空内容标签 |
|---|---|---|
| 结束标签 | 不允许有 | 必须有 |
| 子内容 | 永远不能有 | 可以有,只是当前为空 |
| 示例 | <br> <img> <input> | <div></div> <span></span> |
innerHTML | 无意义 | 为空字符串 |
浏览器如何解析空标签
浏览器的 HTML 解析器对空标签有特殊处理逻辑:
来看一个实际的例子:
<!-- 你写的代码 -->
<img src="a.png">这段文字会怎样?</img>
<!-- 浏览器实际解析为 -->
<img src="a.png">
这段文字会怎样?
浏览器会忽略 </img> 结束标签,把"这段文字会怎样?"当作 <img> 的兄弟节点而非子节点。
使用 JavaScript 操作空标签
空标签在 DOM 操作中有一些特殊行为:
const img = document.querySelector('img');
const div = document.querySelector('div');
// children 和 innerHTML
console.log(img.children.length); // 0 —— 永远为 0
console.log(div.children.length); // 可能为 0,也可能有子元素
// 尝试给空标签添加子元素(不会报错,但没有视觉效果)
img.innerHTML = '<span>test</span>';
console.log(img.innerHTML); // '<span>test</span>' —— 虽然设置了,但不会渲染
// 通过 appendChild 添加子节点
const span = document.createElement('span');
img.appendChild(span);
// DOM 中 img 确实有了子节点,但浏览器不会渲染它
虽然 JavaScript 允许你向空标签中插入子节点(不会抛出错误),但浏览器不会渲染空标签内的子内容。这是 HTML 规范层面的限制,而非 DOM API 的限制。
实际开发中的注意事项
1. alt 属性不能省略
<img> 的 alt 属性对可访问性至关重要:
<!-- ❌ 缺少 alt -->
<img src="banner.jpg">
<!-- ✅ 有 alt -->
<img src="banner.jpg" alt="网站首页横幅">
<!-- ✅ 装饰性图片使用空 alt -->
<img src="divider.png" alt="">
2. 设置图片尺寸防止 CLS
不设置宽高的图片会导致累积布局偏移(CLS):
<!-- ❌ 没有尺寸,加载时页面会跳动 -->
<img src="photo.jpg" alt="照片">
<!-- ✅ 设置尺寸,浏览器提前预留空间 -->
<img src="photo.jpg" alt="照片" width="800" height="600">
3. <input> 要配合 <label>
<!-- ❌ 没有关联 label,可访问性差 -->
<input type="text" placeholder="用户名">
<!-- ✅ 使用 label 关联 -->
<label for="username">用户名</label>
<input type="text" id="username" placeholder="请输入用户名">
4. 避免滥用 <br>
<!-- ❌ 用 br 做布局间距 -->
<div>
内容A
<br><br><br>
内容B
</div>
<!-- ✅ 用 CSS 控制间距 -->
<div>
<p class="mb-4">内容A</p>
<p>内容B</p>
</div>
面试高频问答
Q1:HTML 中有哪些空标签(Void Elements)?
答:HTML5 规范中定义的空标签有:<area>、<base>、<br>、<col>、<embed>、<hr>、<img>、<input>、<link>、<meta>、<param>(已废弃)、<source>、<track>、<wbr>。日常开发中最常用的是 <br>、<img>、<input>、<hr>、<meta>、<link>、<source> 这 7 个。
Q2:<br> 和 <br /> 有什么区别?
答:在 HTML5 中两者都是合法的,没有功能区别。<br> 是 HTML5 的推荐写法,<br /> 是 XHTML 的风格。在 JSX(React)中,由于 JSX 基于 XML 语法要求所有标签必须闭合,所以必须使用 <br />。
Q3:空标签能不能写结束标签?
答:在 HTML5 中,空标签不允许有结束标签。写 <br></br> 或 <img></img> 是不符合规范的。虽然浏览器的容错机制不会报错,但结束标签会被忽略,标签内的内容会被解析为兄弟节点而非子节点,可能导致意外行为。
Q4:空标签和自闭合标签是一回事吗?
答:严格来说不完全是。"空标签"(Void Elements)是 HTML 规范定义的一类不能有子内容的元素。"自闭合标签"(Self-closing Tags)是一种书写形式(如 <br />)。在 HTML5 中,只有空标签可以使用自闭合写法,普通标签写成自闭合(如 <div />)在 HTML 中会被当作开始标签处理(不会自动关闭)。但在 JSX 中,<div /> 是合法的自闭合写法。
Q5:为什么 <img> 的 alt 属性很重要?
答:alt 属性有三个重要作用:
- 可访问性:屏幕阅读器会朗读
alt文本,让视障用户了解图片内容 - SEO:搜索引擎通过
alt文本理解图片内容,有助于图片搜索排名 - 容错展示:图片加载失败时,浏览器会显示
alt文本作为替代
如果图片是纯装饰性的,应设置 alt=""(空字符串),而非省略该属性。
Q6:用 JavaScript 能给空标签添加子元素吗?
答:DOM API 层面是允许的,调用 appendChild 或设置 innerHTML 不会报错,空标签的 DOM 节点中也确实会有子节点。但浏览器不会渲染空标签中的子内容,这是 HTML 规范的渲染规则决定的,所以在实际开发中这样做没有意义。
Q7:<input> 为什么是空标签,而 <textarea> 不是?
答:这是由元素的设计用途决定的:
<input>的值通过value属性来设置,不需要在标签之间放内容<textarea>的默认值需要写在开始标签和结束标签之间,所以它不是空标签
<input type="text" value="通过属性设置值">
<textarea>通过标签内容设置默认值</textarea>
这也解释了为什么 <select> 不是空标签 —— 它需要在内部包含 <option> 子元素。