很多新手刚接触 Web 前端开发时,面对一堆 HTML 标签容易晕:什么时候用 div,什么时候用 section,a 标签和 button 到底有什么区别,表单里的 input 为什么有那么多 type。我做了几年前端,踩过不少标签使用不当的坑,这篇文章就把“常用的 html 标签与说明”完整梳理一遍,不讲虚的,直接告诉你每个标签干什么、什么时候用、有哪些容易犯的错,适合刚入门或者写代码全靠复制粘贴的同学反复对照。
1. 先搭骨架:页面结构类标签的分工
1.1 html、head、body 到底是干什么的
任何一个 HTML 页面最外层一定是 <html>,它告诉浏览器“从这儿开始是一份 HTML 文档”。里面只有两个直接子级:<head> 和 <body>。<head> 放的是页面元信息,比如 <meta>、<title>、<link>、<style>、<script>,这些内容不会直接显示在页面上,但是对浏览器解析、SEO、样式加载至关重要。<body> 才是用户真正看得见、摸得着的部分,你的所有文本、图片、按钮、表单都要写在 <body> 里面。
实际开发中要特别注意 <head> 里的 <meta charset="UTF-8">,少了这一行,中文页面可能出现乱码。<meta name="viewport" content="width=device-width, initial-scale=1.0"> 也是移动端适配的必备项,几乎每个响应式项目都得加。<title> 标签直接影响浏览器标签页显示和搜索排名,别只写“首页”,最好带上品牌词和页面核心词。我见过不少同学把 <div> 直接写在 <html> 外面,或者 <body> 里塞了多个 <head>,这些都会导致浏览器自动纠错,后期维护时非常痛苦。
1.2 标题标签 h1~h6 与段落 p 的使用边界
标题标签一共六级,从 <h1> 到 <h6>,字号依次递减,语义上重要性也依次递减。一个页面最好只有一个 <h1>,它通常是页面主标题,搜索引擎主要靠它判断页面主题。<h2> 可以有很多个,用来划分章节,<h3> 再往下作为子章节。不要为了字体大小去用标题标签,如果你想控制字号,请用 CSS,标签负责语义,CSS 负责长相。
<p> 是最常用的文本容器,代表一个自然段落。段落之间默认有间距,如果你只想要换行但不换段,用 <br>。<br> 是强制换行,没有结束标签,也不要拿来制造大量空白,那是 CSS 的 margin 该干的事。<hr> 是水平分割线,同样没有结束标签,在语义上表示主题切换,不是单纯的装饰线。
这里有个常见的错误:把一堆 <p> 里面再嵌套 <div> 或者直接把 <h1> 到 <h6> 当成普通文字。HTML 规范要求标题和段落是流式内容容器,可以包含行内元素,但某些场景下过度嵌套会破坏可访问性。我自己的习惯是:正文一律用 <p>,标题按层级用 h1~h6,需要居中或改色再交给 class。
1.3 列表标签:ul、ol、dl 怎么选
列表类标签有三种,很多人只会用 ul 加 li,其实选错会影响语义和样式。<ul> 是无序列表,列表项之间没有先后顺序,适合导航菜单、商品列表、新闻列表等;<ol> 是有序列表,列表项有明确的先后关系,适合步骤说明、排行榜、操作流程;<dl> 是描述列表,由 <dt>(术语)和 <dd>(描述)组成,适合做名词解释、键值对数据,比如用户信息展示页“姓名:张三、年龄:18”这类结构。
ul 和 ol 的直接子元素必须是 <li>,不要在 <ul> 下面直接写 <div> 或 <span>。如果确实需要包一层容器,先把 li 写好,再在 li 里面嵌套其他内容。li 里面可以放很复杂的结构,比如图片加标题加描述,这没问题,但外层必须是 ul 或 ol。
还有一点容易被忽略:列表的默认样式在不同浏览器里略有差异,ul 的圆点、ol 的数字序号有时不符合设计稿。处理办法是在 CSS 里设置 list-style: none 并自定义图标,或者用 list-style-position 控制序号位置。但语义上不要因为“想去掉点”就把 ul 改成 div,屏幕阅读器需要通过列表结构判断内容组织方式。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 内容呈现:文本、链接、图片与媒体标签
2.1 strong、em、b、i、span 在什么时候用
这四个标签长相容易混,语义却完全不同。<strong> 表示内容重要性很强,屏幕阅读器会加重语气,浏览器默认加粗;<em> 表示强调,通常斜体显示;<b> 只是视觉加粗,没有特殊语义;<i> 只是视觉斜体,没有特殊语义。HTML5 规范鼓励用有语义的 <strong> 和 <em>,<b> 和 <i> 属于“无奈之选”,比如产品名、专业术语、图标字体这种没有其他更合适标签的时候可以用。
<span> 是纯粹的行内容器,没有任何语义,它的唯一作用就是你需要在文本中间包一部分内容,然后用 class 给它加样式或绑定事件。比如一句话里某个词要变红,就用 <span class="red">某个词</span>。但不要用 <span> 包一大块区块,那是 <div> 的职责。行内元素嵌套行内元素没问题,行内元素不要嵌套块级元素。
实际项目里,我一般这样处理:关键词加粗用 <strong>,某个字需要点缀但不想影响语义用 <span>。如果只是编辑器里加了个粗体按钮,生成出来的 <b> 也能接受,但代码评审时我会建议改成 <strong>。
2.2 a 标签的各种跳转方式与性能细节
<a> 是超链接标签,核心属性是 href,指向链接地址,也可以是 mailto:、tel: 等专用协议。target 控制打开方式,_blank 表示新标签页打开,_self 是当前页打开。用 _blank 时最好加上 rel="noopener noreferrer",原因是从安全角度讲,新打开的页面默认能通过 window.opener 拿到原页面的引用,存在被钓鱼或性能拖慢的风险,加上 noopener 之后就隔离了这种能力。
a 标签可以包裹很多内容,但不应该包另一个可交互元素,比如 <a> 里面放 <button> 或另一个 <a>,这会导致点击行为混乱。如果一段文字既能跳转又能提交表单,应当拆分成两个独立操作。对于“下载文件”这类需求,可以在 a 标签加 download 属性,浏览器会尝试下载而不是打开。不过 download 属性对跨域资源不一定生效,这点要提前知道。
有时候需要让整块卡片可点击,很多人会Boxed整个 <div> 套一个 <a>,这在 HTML5 里是合法的,但要注意不能让 a 的块级子元素里再嵌套交互元素。更稳妥的方案是给卡片绑定 JS 点击事件并配合键盘访问支持,或者用一个覆盖整块的伪链接。
2.3 img 图片标签的常用属性与加载体验
<img> 是行内替换元素,它主要显示图片。必备属性是 src 和 alt。src 是图片地址,alt 是图片加载失败或无法被屏幕阅读器读取时显示的替代文本。alt 不是一个可有可无的东西,它对 SEO 和可访问性都重要。一张功能性的图片,比如图标按钮,alt 应该写清楚操作含义;一张纯装饰图片,alt 可以写空字符串 alt="",这样屏幕阅读器会完全跳过。
width 和 height 建议明确写出来,哪怕 CSS 会覆盖。原因是可以避免图片加载时页面布局上下跳动,也就是常说的 CLS 问题。不写宽高但 CSS 设了 max-width: 100% 的情况,少数浏览器会先按 0 高度渲染,图片加载完再撑开,用户会看到内容突然跳动。
图片加载性能方面,现代项目常用 loading="lazy" 让非首屏图片懒加载,但首屏图片不要用懒加载,否则会影响 LCP。srcset 属性可以配合不同屏幕密度给不同尺寸图片,是响应式图片的核心手段。真要处理一大堆图片,还是建议走专门的图片 CDN 或云存储处理方案,标签层面只负责正确引用。
2.4 音频、视频与 iframe 嵌入
<audio> 和 <video> 是 HTML5 提供的媒体标签,src 指定媒体地址,controls 属性会显示播放控件。video 还支持 poster 属性,显示加载前的封面图。要注意浏览器对媒体格式的兼容性:常见的 mp4 基本都能放,但某些格式需要转码。autoplay 属性在大多数浏览器里会被拦截,除非把声音静音掉,也就是 muted 配 autoplay 才能生效,这条规则避免了很多烦人的自动播放问题。
<iframe> 用于在当前页面嵌入另一个文档,比如嵌入视频播放器、地图、第三方页面。它有一个很实用的属性 loading="lazy",可以让非首屏 iframe 延迟加载。title 属性对于屏幕阅读器特别重要,否则用户不知道这个框架里是什么内容。出于安全考虑,很多第三方服务会通过 X-Frame-Options 拒绝被嵌入,所以遇到 iframe 空白不要怀疑代码写错,先检查目标网站是否允许被嵌入。
3. 页面交互:表单与表格标签的实用要点
3.1 table 表格标签的语义结构与现代用法
过去的网页布局经常用 <table> 来搭建整个页面结构,那是很古老的做法。现在的表格标签只用来展示真正的表格数据。一个完整的表格由 <table> 包裹,<thead> 定义表头,<tbody> 定义表身,<tfoot> 定义表尾,行用 <tr>,单元格用 <td>,表头单元格用 <th>。<th> 默认加粗居中,但在语义上更重要的是它标识了列和行的关系,屏幕阅读器可以利用这个关系把数据和表头对应起来。
给表格加边框是很多初学者的第一个难点,因为默认情况下表格是没有边框的。用 CSS 设置 border-collapse: collapse 可以让相邻单元格的边框合并,看起来干净。colspan 表示单元格横跨几列,rowspan 表示竖跨几行,这两个属性在处理复杂表头时经常用到。响应式表格是另一个难点,因为表格在窄屏上很容易撑破布局,常见的方案是外层包一个 overflow-x: auto 的容器,或者把表格改成卡片式布局。
表格标签还有一个容易被忽视的点:每一个 <th> 都应该有对应的作用域,如果是列标题加 scope="col",行标题加 scope="row"。虽然普通用户看不到效果,但对辅助技术是质的提升。我做无障碍改造时遇到最多的问题就是表格没有表头,或者表头用了 <td> 加粗代替,这类代码必须重写。
3.2 form 表单与 input 的常用 type 详解
<form> 是表单的容器,核心属性是 action(提交地址)和 method(提交方式,常用 get 和 post)。action 不写的话默认提交到当前页面地址,很多新手以为不写就没事,结果点击提交后页面刷新了。更稳妥的做法是在前端绑定 submit 事件并调用 preventDefault(),然后走 Ajax 提交,这样就不依赖 action 了。
<input> 是表单里用途最广的标签,它靠 type 属性区分类型。最常用的有:
text:单行文本,默认输入框password:密码输入框,内容会显示为点或星号email:带邮箱格式校验的输入框number:只能输入数字,有上下箭头checkbox:复选框,多选radio:单选框,需要同 name 才能互斥file:文件选择框hidden:隐藏字段,用于页面间传值submit和button:提交按钮和普通按钮
radio 单选框有个经典坑:一组单选按钮必须设置相同的 name 属性,否则它们不互斥,可以同时选中。checkbox 和 radio 的默认样式不同系统长得不一样,做自定义样式时通常先把默认外观 appearance: none 去掉,再画自己的样式。但这样做要注意不能把键盘可访问性丢掉,焦点态仍需保留。
3.3 select、textarea、label 的配合使用技巧
<select> 是下拉选择框,<option> 是它的选项,selected 属性表示默认选中。有些产品需要“多选下拉”,可以给 select 加 multiple 属性,但体验很差,一般会用自定义组件。<textarea> 是多行文本输入框,rows 和 cols 可以控制默认行数和列数,但更建议用 CSS 的 width 和 height 来控制尺寸,resize 属性可以禁止用户拖拽调整大小。
<label> 可能是最被低估的标签。它用来把一段说明文字和一个表单控件关联起来。写法有两种:一种是用 for 属性指向控件的 id,另一种是直接把控件嵌套在 label 里。关联之后,用户点击文字就等于点击控件,这极大提升了可点击区域,特别是对单选框和复选框。同时,屏幕阅读器也会把 label 的文字读给用户,是可访问性的关键一环。
实际做表单时,注意 input 的 name 属性,它是提交数据时字段的键名,没有 name 的 input 不会被提交。placeholder 是占位提示,不能替代 label,因为当用户开始输入时提示消失,如果用户忘了要填啥,只能靠 label 来提示。所以规范做法是 label 永远存在,placeholder 只做补充。
4. 组合与布局:div、span 与 HTML5 语义化标签
4.1 div 是布局容器但不是万能药
<div> 是块级无语义容器,它本身不表示任何含义,只是用来给内容分组,方便布局和加样式。几乎每一个现代网页都有大量 div,这没什么好羞愧的。但问题是很多人不管三七二十一,所有内容全用 div 包裹,甚至列表、段落、按钮都用 div 模拟,这就丢失了语义,让搜索引擎和辅助技术没法理解页面。
合理的用法是:在需要“纯粹为了布局”的地方用 div,比如栅格系统的列、弹窗的背景遮罩、轮播图的滑动容器。只要内容本身有更合适的语义标签,比如标题、段落、列表、导航,就不要用 div 替代。span 是行内无语义容器,它和 div 的区别只在显示方式:span 不会换行,div 会换行并占据一整行。如果你只是想给一段文字里的某个词标个颜色,用 span;如果你想包裹一个区块并让它独占一行,用 div。
4.2 HTML5 语义化标签:header、nav、main、footer 怎么用
HTML5 引入了一组真正有语义的结构标签,能减少 div 泛滥。<header> 通常放页面的头部区域,比如 logo、导航、搜索框。<nav> 放导航链接,一般是一个 ul 列表包装起来。<main> 表示页面主体内容,一个页面最好只有一个 main,不要把侧边栏、页脚也塞进去。<footer> 放页脚的版权信息、友情链接等。<section> 表示一个独立的章节,通常带一个标题。<article> 表示一篇完整的文章或独立组件,比如一篇博客、一条评论、一个商品卡片。
这些都是块级元素,默认样式基本和 div 一样,所以视觉上你感觉不到太大区别。但在代码结构上,用 header、nav、main、footer 代替无名 div,能让团队协作效率显著提升:新同事打开页面,一眼就知道哪里是头部哪里是主内容。搜索引擎也能更好地提取页面结构,有机会展示更丰富的搜索结果。
section 和 article 的选择是个经典问题。简单记:article 强调“独立可分发”,页面里把它单独拿出来还能完整理解;section 强调“分节”,通常是文章或者页面的一个组成部分。一篇文章可以用 article 包裹,里面再用多个 section 分章节。如果只是样式容器,没有语义需求,直接用 div,不要硬造语义。
4.3 全局属性:id、class、data-* 与 aria
id 是全局唯一的标识符,同一个页面里不允许出现两个相同 id。它在三处地方最常用:label 的 for 指向、CSS 选择器、JS 获取元素。由于 id 唯一,JS 里可以用 getElementById 快速拿到元素。class 可以重复,一般用于样式复用,多个 class 用空格隔开,比如 class="btn btn-primary"。
data-* 是自定义数据的官方方案,比如 <div data-id="123" data-type="product">,JS 里可以用 dataset.id 和 dataset.type 读取。一定不要把状态直接写在 class 名称里然后靠样式判断,比如 class="active" 确实常见,但真正稳定的是用 data-state="active" 或 aria 状态属性来承载状态。
aria-* 是可访问性属性,常见的有 aria-label(给元素加一个可读名称)、aria-hidden="true"(让辅助技术忽略该元素)、aria-expanded(表示手风琴或菜单展开状态)。做前端不能只给看得见的人用,键盘用户和屏幕阅读器用户同样应该能操作你的页面。很多人觉得无障碍是加分项,实际在很多行业项目里已经是硬性要求。从标签层面就规范起来,后面改动会轻松很多。
5. 常见问题与排查技巧实录
5.1 标签不生效或样式错乱的常见原因
先讲最容易遇到的问题:写了标签却不起作用。比如 button 的 type 默认是 submit,如果你把它放在一个 form 里,那么点击就会触发表单提交,页面刷新,看起来“按钮按了没反应”,其实是被提交刷新了。解决办法是给非提交按钮加 type="button"。类似的还有 a 标签如果没有 href,默认不是可聚焦的链接,也几乎没有点击效果,所以如果你做一个“按钮样式的链接”,一定要有 href。
标签嵌套错也会导致样式错乱。浏览器遇到非法嵌套时会自动解析纠正,比如 <p> 里面套 <div>,浏览器会把 div 拆出去,最终结构和你预想完全不一样,高度、间距、背景色全都乱。排查这类问题的最佳方式不是猜,而是打开 DevTools 的 Elements 面板,看真实的 DOM 结构,浏览器已经告诉你它实际渲染成了什么。
另一种常见问题是中文乱码。页面中文乱码十有八九是因为缺 <meta charset="UTF-8">。注意这个 meta 必须出现在 <head> 的最前面,否则也可能被解析器在开头用默认编码读了一部分,导致错误。这个标签在模板里很容易被遗漏,每次创建新页面时务必检查第一行。
5.2 块级元素与行内元素的嵌套禁忌
HTML 标签按显示方式大致分为块级和行内,但 HTML5 之后更严谨的分类是“流式内容”和“短语内容”。简单实践规则:块级元素可以包含行内元素或其他块级元素,但行内元素不能包含块级元素。比如 <span> 里放 <div>,<a> 里放 <h1>,这些都会导致浏览器解析错误,并且样式不可控。<p> 比较特殊,它虽然是块级,但规范规定它不能包含块级元素,所以 <p> 里放 <div> 是非法嵌套。
有个必须记住的小团队规范:如果要包一大块内容,用 div 或语义化块级标签;如果只是文字中的一小段变化,用 span。做结构时先看内容本质上是什么,再选标签,而不是先写一堆 div 再想办法修样式。
5.3 特殊字符显示与转义
在 HTML 中,有些字符是保留字符,直接写会被浏览器误解。比如 < 和 > 是标签的边界,如果要在页面上显示“a < b”,直接写 < 会被当作一个不完整标签的开头。& 是实体字符的起始符号,直接写也容易出错。正确做法是用字符实体:< 代表 <,> 代表 >,& 代表 &, 是不换行空格。因为 & 特殊,实体本身在代码里写的时候要注意顺序,比如显示“<”这段文字,要写 &lt; 才行。
空格处理也是常见问题:连续多个空格在 HTML 里只会渲染为一个。如果你必须保留多个空格,用 ,或者用 CSS 的 white-space: pre。但大多数情况下,间距应该由 CSS 的 margin/padding 控制,不要依赖空格字符。
5.4 一个日常开发的标签自查清单
为了避免项目后期返工,我给自己规定了一套检查清单,每次写完页面结构都会过一遍:
- 页面是否只有一个
<h1>,标题层级是否跳级 - 所有
img是否有alt,装饰性图片是否alt="" - 所有表单控件是否都有对应
label - 按钮是否明确设置了
type,尤其是 form 内部的按钮 a标签target="_blank"时是否携带了rel="noopener"- 列表项目是否都写在了
ul/ol的直接子级li中 - 结构上是否错误使用了
div替代语义标签 - 每个页面的
lang属性是否设置正确,比如中文页面用lang="zh-CN"
这套清单写不进 eslint 规则的部分,就是靠人工 review 时翻一遍。经验多了之后,你会发现标签选错导致的返工,往往比写样式和调逻辑更麻烦。与其后期用各种 hack 去修,不如一开始就把标签用对。
我在实际开发里的体会是:HTML 标签不是背出来的,是悟出来的。你天天写 div 也能做出页面,但当你某一天要改一个老项目,发现里面全是 div 套 div,想加一个事件却不知道哪个才是真正的按钮时,你就会明白当初为什么要把标签写规范。推荐你从今天起写代码时多问自己一句“这个内容本质是什么”,然后挑一个最接近它的标签。坚持一个月,你的 HTML 水平会有非常明显的提升。
