必须且只能出现一次,因其是页面唯一语义锚点,用于搜索引擎权重分配和屏幕阅读器“m键直达”,重复会触发lighthouse警告、导致辅助技术忽略后续内容,并破坏可访问性与seo。

语义化标签在大型项目里不是“锦上添花”,而是降低协作熵值、规避可访问性合规风险、减少SEO返工的刚性基建。
为什么 <main></main> 必须且只能出现一次
它不是视觉容器,而是告诉浏览器和辅助技术“这里开始是页面唯一主内容区”。搜索引擎会据此分配权重,屏幕阅读器用 main 作为跳转锚点(如按 M 键直达)。多次出现会触发 Lighthouse 可访问性警告 "Document has more than one <main> element"</main>,也导致部分读屏软件忽略后续 <main></main> 内容。
- 实际项目中常见错误:组件库封装了带
<main></main>的卡片,在循环渲染时重复插入 - 修复方式:只在最外层路由级组件中用一次
<main></main>,子组件改用<section></section>或<div role="region"> <li>CI/CD 中可加 HTMLHint 规则:<code>"html-req-lang": true和"html-valid-main": true - 错误示例:把“产品列表页”整个包进
<article></article>—— 列表本身不是独立内容,每条产品才是 - 正确做法:列表页用
<main></main>包裹,每个产品项用<article></article>,分类区块(如“热销榜”“新品推荐”)用<section></section>并加<h2></h2> - 注意:嵌套
<article></article>是允许的(如评论嵌套在文章内),但<article></article>内部不应再出现<main></main>或<header></header>(除非是其自身子内容的 header) - 典型场景:注册页的“兴趣偏好”多选区域,没
<fieldset></fieldset>就是一串孤立的<input type="checkbox"> - 修复后效果:读屏软件朗读“兴趣偏好,复选框,科技”——
<legend></legend>提供上下文,<input>提供具体选项 - 兼容性提示:IE11 支持
<fieldset></fieldset>,但若配合display: contents清除边框,需测试是否破坏语义树(某些旧版 NVDA 会丢弃)
<article></article> 和 <section></section> 的边界在哪
<article></article> 是自包含、可独立分发的内容单元(比如一篇博客、一条新闻、一个用户评论),脱离当前页面仍能被理解;<section></section> 是逻辑区块,必须有主题,且通常配一个 <h2></h2>–<h6></h6> 标题。混淆二者会导致结构语义失真,影响爬虫提取准确率。
表单里不用 <fieldset></fieldset> 和 <legend></legend> 的真实代价
它们不只是“加个边框”,而是为屏幕阅读器构建语义分组树。缺少 <legend></legend> 时,读屏软件无法告知用户“这组复选框属于哪个功能模块”,用户得逐个听控件名猜意图。
真正容易被忽略的,是语义标签与动态内容的耦合问题:SPA 路由切换时,<main></main> 的 aria-live 属性要不要更新?<article></article> 加载完成是否该触发 document.getElementById("article-123").focus()?这些不是“写完就完”的事,而是每次 DOM 更新都要重新校验的链路。











