必须全局唯一且仅包裹核心内容,否则屏幕阅读器会跳过或定位错误;它不是视觉容器而是导航锚点,需自带语义化标题并支持独立分发,构建时须用htmlhint等工具强制校验。

<main></main> 必须全局唯一,且只包裹用户真正要操作或阅读的核心内容;违反这点,屏幕阅读器会跳过、定位错、响应慢——这不是“写得不够好”,而是直接让辅助技术失效。
为什么 <main></main> 不能嵌套在 <header></header> 或 <nav></nav> 里
它不是视觉容器,是辅助技术的导航锚点。屏幕阅读器按 M 键跳转时,只认第一个合法 <main></main>;如果被包在 <header></header> 里,读屏工具可能直接忽略,或把 banner、logo 当成主内容播报。
- Next.js / React Router 布局组件中提前写了
<main></main>,子页面又渲染一个 → 实际 DOM 出现多个,CI 不报错但可访问性已崩 - Vue 模板中用
v-if控制不同视图,但都套了<main></main>→ 构建后静态 HTML 里仍存在多个声明 - 修复方式:只在最终页面组件(如
ArticlePage.vue)顶层用一次<main></main>,布局层彻底移除
<section></section> 和 <article></article> 的边界在哪
误用比不用更危险。<section></section> 不是带标题的 <div>,<code><article></article> 也不是“看起来像卡片”的容器。
-
<section></section>必须自带<h2></h2>–<h6></h6>,且该标题能概括整个区块主题;否则优先用<div> <li> <code><article></article>内容必须可独立分发(RSS 抓取、邮件推送、搜索引擎摘要),评论区、博客正文、产品详情页适用;导航菜单、广告位、页脚链接列表不适用 - 常见错误:
<section><p>欢迎光临</p><div class="aritcle_card flexRow"> <div class="artcardd flexRow"> <a class="aritcle_card_img" href="/xiazai/skill10246" title="HTML Text Extract"><img src="https://img.php.cn/upload/skill/001/246/273/6adaf20dee630206.jpg" alt="HTML Text Extract" ></a> <div class="aritcle_card_info flexColumn"> <a href="/xiazai/skill10246" title="HTML Text Extract">HTML Text Extract</a> <p>从HTML页面(URL、文件或标准输入)中提取主体内容文本,去除导航、页脚、广告和模板文本。可直接传递给readability_check或其他文本工具。</p> </div> <a href="/xiazai/skill10246" title="HTML Text Extract" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a> </div> </div> <p><span>立即学习</span>“<a href="https://pan.quark.cn/s/cb6835dc7db1" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">前端免费学习笔记(深入)</a>”;</p></section>(无标题)、<article><div class="card-header">…</div></article>(无语义标题、不可分发) - 必须在构建脚本中调用
htmlhintCLI,失败时中断构建;推荐接入 Vite 插件vite-plugin-htmllint或 Webpack 的html-webpack-plugin+htmlhint-loader -
.htmlhintrc至少启用:id-unique、img-alt-require、head-script-disabled、attr-lowercase、main-unique - JS 动态拼接的 HTML(如
innerHTML = `<section>...`</section>)需额外用remark-html+remark-lint在源码层校验,不能依赖运行时
构建流程里怎么拦住语义错误
VS Code 插件提示 ≠ 工程化落地。本地没开插件、PR 提交绕过编辑器、CI 流程没集成,等于没设防。
最容易被忽略的是标题层级断裂:页面从 <h2></h2> 开始、<main></main> 外堆了三个 <h1></h1>、小节用了 <h3></h3> 但主内容还没出现 <h2></h2>——这会让文档大纲(outline)彻底失效,而所有依赖它的工具(axe-core、Lighthouse、NVDA)都会误判结构。


















