语义化关键在正确使用而非堆砌标签:唯一且不可嵌套,须独立分发,必有标题,限主导航,/可多层嵌套绑定父元素,需datetime属性,须直包,冲突时应回退+aria。

绝大多数语义化问题,不是“该不该用”,而是“用错位置”或“用错标签”。真正起作用的只有 <nav></nav>、<main></main>、<header></header>、<footer></footer>、<article></article>、<time></time> 和 <figure></figure>+<figcaption></figcaption> 这几组,其余多数属于“写了不如不写”,甚至干扰辅助技术。
哪些标签必须严格守边界,否则直接破坏可访问性
这几个标签一旦越界,屏幕阅读器和搜索引擎就可能跳过关键内容,或把结构理解成完全相反的意思:
-
<main></main>全局只能出现一次,且不能嵌套在<article></article>、<aside></aside>、<section></section>、<nav></nav>、<header></header>、<footer></footer>内部;它里面也不能塞导航栏、侧边栏、页脚版权信息 -
<article></article>必须满足“独立分发”:整块复制出去,能被 RSS 订阅、被单独打印、被转发到其他平台仍语义完整;博客正文、新闻稿、用户评论可以,但“热门标签云”或“相关推荐列表”不行 -
<section></section>不是视觉分块工具——它必须有明确主题,且内部应包含<h2></h2>–<h6></h6>标题;没有标题的<section></section>对辅助技术等于空标签 -
<nav></nav>只用于“主要导航路径”,比如顶部菜单、左侧栏目树;页脚一堆友情链接、文章末尾的“上一篇/下一篇”,通常不算,加aria-label="pagination"后再用更稳妥
<header></header> 和 <footer></footer> 其实能嵌套多次,但很多人不敢用
它们不是页面级专属标签,而是“就近绑定章节根元素”的区域容器。这意味着:
- 一个
<article></article>可以自带<header></header>(含<h2></h2>+<time datetime="2026-08-20"></time>),也可以自带<footer></footer>(含作者信息、分享按钮) -
<header></header>里不强制放<h1></h1>;页面级<header></header>放<h1></h1>是惯例,但模块级<header></header>用<h2></h2>才符合大纲逻辑 - 多个
<footer></footer>并存没问题,但每个都应服务其最近的父容器:页面底部的<footer></footer>属于,而某篇<article></article>底部的<footer></footer>就只属于那篇文章
<time></time> 和 <figure></figure> 这两个细节标签,不用等于白搭语义
它们不起眼,但却是机器识别时间、图文关系的关键入口,漏掉会直接丢失 SEO 时效性和无障碍播报能力:
-
<time></time>的datetime属性必须是机器可读格式(如"2026-08-25"或"2026-08-25T14:30"),只写<time>今天</time>对屏幕阅读器无效;日期聚合、日历同步、搜索结果排序都依赖这个属性 -
<figure></figure>必须包裹图像、图表、代码块等“自包含媒体内容”,<figcaption></figcaption>必须是它的**直接子元素**;写成<div><figure>...</figure></div>没问题,但写成<figure><div><figcaption>...</figcaption></div></figure>就断开了图文关联 -
<figure></figure>不等于“带标题的图”——广告图、装饰性 icon、纯 CSS 背景图都不适用;它强调的是“内容完整性”,比如一张数据折线图+它的解读说明,才构成一个<figure></figure>
什么时候该退回 <div>,而不是硬套语义标签
<p>语义标签不是越多越好。当标签自带的隐含含义和你的内容逻辑冲突时,强行使用反而制造歧义:</p>
<ul><li>仪表盘里的“实时订单卡片”,既不是可独立分发的 <code><article></article>,也不是有标题的逻辑分区 <section></section>,用 <div role="region" aria-labelledby="order-card-title"> 更准确
<li>CSS Grid / Flex 布局容器本身只是布局意图,不表达内容角色;给 <code><div class="grid-container"> 加 <code><section></section> 会误导辅助技术认为“这里有个新章节”
<template></template> 内禁止出现 <main></main>、、 等顶级语义容器;克隆后插入的位置,必须由 JS 补全上下文语义(比如插入到 <main></main> 内才算合法)最常被忽略的一点:语义是否生效,不看浏览器渲染效果,而要看开发者工具的 Accessibility 面板生成的大纲树——如果 <article></article> 下面没 <h2></h2>、或者 <section></section> 出现在 <main></main> 外层,大纲树就会断裂,所有语义努力都归零。











