语义标签选择需依内容角色而定:有明确大纲标题且独立成文用,仅布局或交互容器用,头部、导航、主内容区等必须用等语义元素。

判断一块内容该用 <section></section> 还是 <div><ul>
<li>它有没有一个能写进大纲的标题?比如 <code><h2>客户案例</h2> 或 <h3>安装步骤</h3> —— 没有,就别用 <section></section>
<article></article>;不能但内部有明确主题 → <section></section>;只是布局容器 → <div> <li>你正在写的是“最新文章列表”这个区域,那整个容器是 <code><section></section>;但每篇文章本身,应该用 <article></article>,不是 <section></section> <section></section> 不提供默认样式,视觉上和 <div> 一样“空白”,别因为看不出区别就乱换 <h3>什么时候必须用 <code><header></header>、<nav></nav>、<main></main> 而不是 <div class="xxx"><ul><li>
<code><header></header>:页面顶部或某个 <section></section> 里的头部(含 logo、主标题、主导航),屏幕阅读器会播报“进入头部区域”;<div class="header"> 只是普通区块,辅助设备读作 “division” <li>
<code><nav></nav>:只包裹全站级主导航(顶部菜单、左侧全局导航),面包屑、页脚链接、文章内“上一篇/下一篇”不算;<div class="nav"> 不支持 Ctrl+Alt+N 快捷跳转 <li>
<code><main></main>:每个页面有且仅有一个,代表主体内容,不能嵌套在 <article></article> 或 <section></section> 内部;用 <div class="main"> 会让爬虫无法识别核心内容区 <h3>哪些场景只能老实用 <code><div>,硬套语义标签反而出错
<ul><li>做 CSS Grid / Flex 的直接父容器:比如 <code><div class="grid-container">,纯为样式服务,无语义需求 <li>JS 动态挂载点:如 <code><div id="root">、<code><div data-chart-id="revenue-q2">,这类节点不参与文档语义流 <li>表单字段分组、下拉菜单容器、卡片内图标列表——它们是交互/布局单元,不是独立内容区块 </li>
<li>用 <code><div> 包了多个 <code><h2></h2> 却没用 <section></section>,或者给 <div class="card"> 加了 <code>role="article" 却没升级为 <article></article>,都是语义污染信号 验证语义是否真的生效的最简方法
- 关掉所有 CSS,用 Tab 键遍历页面:如果导航前要按十几次 Tab 才到,大概率是
<nav></nav> 缺失或被 <div> 替代了 <li>Chrome DevTools → Elements → 右键节点 → Inspect Accessibility Properties:看是否大量显示 generic 类型,或本该是 navigation 的节点标成了 complementary </li>
<li>检查 <code>document.body.querySelectorAll('section') 返回的数量是否合理——突然多出十几个,但页面其实只有三块逻辑分区,说明误用了
-
<section></section> 里没配 <h2></h2>–<h6></h6>,它在 NVDA / VoiceOver 中基本等于不存在,CSS 选择器也失去结构锚点
真正难的不是记住规则,而是每次写标签前停半秒:这个容器,到底是“内容角色”,还是“控制角色”。前者交给语义标签,后者留给 <div>。</div>
<nav></nav> 缺失或被 <div> 替代了 <li>Chrome DevTools → Elements → 右键节点 → Inspect Accessibility Properties:看是否大量显示 generic 类型,或本该是 navigation 的节点标成了 complementary </li>
<li>检查 <code>document.body.querySelectorAll('section') 返回的数量是否合理——突然多出十几个,但页面其实只有三块逻辑分区,说明误用了 <section></section> 里没配 <h2></h2>–<h6></h6>,它在 NVDA / VoiceOver 中基本等于不存在,CSS 选择器也失去结构锚点 真正难的不是记住规则,而是每次写标签前停半秒:这个容器,到底是“内容角色”,还是“控制角色”。前者交给语义标签,后者留给 <div>。</div>











