每个页面有且仅能有一个<main>,且不可嵌套在<article>等区域元素内;<main>应包裹全页主要内容,每篇文章用<article>单独包裹,<section>须带标题以确保可访问性。

为什么 <main> 不能随便套在 <article> 外面
很多 Hugo 或 Hexo 用户改模板时,看到 HTML5 结构标签就直接套用,结果导致屏幕阅读器报错、SEO 工具提示“main 元素缺失”或“多个 main”。根本原因是:每个页面**有且仅能有一个 <main>**,且它**不能嵌套在 <article>、<aside>、<footer> 等区域元素内**。
静态博客常见错误写法:
<article>
<main>
<h1>标题</h1>
<p>正文</p>
</main>
</article>
正确做法是让 <main> 包住整页主要内容容器(比如 content 区域),而每篇博文用 <article> 单独包裹:
-
<main>放在layouts/_default/base.html(Hugo)或layout/layout.ejs(Hexo)的主体内容区,且只出现一次 -
<article>放在layouts/_default/single.html或layout/post.ejs内部,每篇文章一个 - 列表页(如首页、归档页)中,每个
<article>应包含<header>+<section>+ 可选<footer>
用 <section> 拆分长文比用 <div> 更安全
Markdown 渲染后常生成大段 <p> 和 <h2>,有人习惯加 <div class="section"> 手动分块。但语义上,<section> 表示“文档中具有主题的独立部分”,更适合用于长文的逻辑分章(如“安装步骤”“配置说明”“常见问题”)。
立即学习“前端免费学习笔记(深入)”;
注意三点:
-
<section>必须有标题(<h2>–<h6>),否则会被辅助技术忽略 - 不要用
<section>替代样式容器——纯为了加 margin/padding,请继续用<div> - Hugo 的
{{ .Content }}默认不解析自定义 HTML 标签,若想在 Markdown 中插入<section>,需启用unsafe渲染或改用短代码(shortcode)封装
Hexo 的 post.ejs 里怎么避免 <aside> 被搜索引擎误判为正文
很多人把侧边栏(目录、标签云、推荐文章)放进 <aside>,但若没加 aria-label 或没放在 <main> 外,某些 SEO 工具会把它和正文一起提取文本,拉低关键词密度。
实操建议:
- 确保
<aside>不在<main>内部;它应与<main>并列,同级放在<body>下 - 给
<aside>加aria-label="related content"或aria-label="table of contents",明确用途 - Hexo 中,
post.ejs常见结构是:<main>...</main><aside>...</aside>,而非把<aside>塞进<article>里 - 如果使用
hexo-toc插件生成目录,它默认输出无语义<ol>,建议包裹一层<nav aria-label="table of contents">而非<aside>
Hugo 的 baseof.html 中 <header> 和 <footer> 容易重复渲染
在 layouts/_default/baseof.html 里写死 <header> 和 <footer> 很方便,但容易忽略两点:
- 某些页面(如 404、隐私页)可能不需要全局导航栏,但
<header>仍被强制渲染 → 解决:用{{ if not .Is404 }}或{{ if .Site.Params.showHeader }}控制显示 -
<footer>若含动态版权年份(如© {{ now.Year }} {{ .Site.Title }}),必须确保它不在partial中被多次 include —— Hugo 的{{ partial "footer.html" . }}如果在多个 layout 中调用,会导致重复输出 -
<header>内的<nav>应有aria-label,例如<nav aria-label="main navigation">,否则无障碍测试失败
HTML5 结构标签不是装饰,它们直接影响爬虫抓取路径和读屏顺序。最常被忽略的是:没有检查 <main> 是否真的唯一,以及是否所有 <section> 都带了可访问标题。











