HTML5语义化标签在Vue中直接使用即可,无需v-html或封装组件;应避免无意义div包裹,优先用语义标签自身作容器;动态切换需用is特性;第三方组件可通过ARIA补救语义。

结构标签直接写就行,不用特殊处理
HTML5 的 <header>、<nav>、<main>、<aside>、<footer> 这些语义化标签在 Vue 模板里和写普通 HTML 一样,直接用,Vue 不会拦截或转换它们。编译后它们就是原生 DOM 元素,无障碍、SEO、屏幕阅读器都认得。
常见误区是以为要加 v-html 或封装成组件才能用——完全不需要。只要不是自闭合错误(比如写了 <main/>)或嵌套违反 HTML 规范(比如 <main> 里放了另一个 <main>),Vue 就能正常渲染。
避免用 <div> 套语义标签破坏可访问性
有些团队习惯把所有区块包一层 <div class="container">,结果变成:
<div class="header-wrapper"> <header>...</header> </div>
这会让辅助技术多绕一层,且可能干扰 <header> 的默认角色(banner)。正确做法是让语义标签自己承担容器职责:
立即学习“前端免费学习笔记(深入)”;
<header class="site-header"> <h1>站点标题</h1> <nav>...</nav> </header>
- 用 CSS 类控制样式,别用无意义的 wrapper
- 如果必须加 wrapper(比如需要 flex 包裹多个语义块),优先用
<section>或<article>这类中性但仍有语义的标签 - 检查浏览器开发者工具的「Accessibility」面板,确认
role和name没被意外覆盖
动态切换语义标签需用 is 特性,不能靠 v-if/v-else
当需要根据 props 动态决定用 <section> 还是 <article> 时,直接写 v-if 会导致 Vue 创建/销毁节点,丢失状态或触发多余重绘。正确方式是用内置的 is 特性:
<component :is="blockType" class="content-block"> <slot></slot> </component>
其中 blockType 是字符串,如 "section" 或 "article"。这样 Vue 复用同一个组件实例,只替换外层标签名。
注意点:
-
is只接受字符串(如"header")或已注册的组件名,不支持表达式拼接 - 若用
is="main",需确保页面只有一个<main>,否则违反 HTML5 规范 - 服务端渲染(SSR)下,
is渲染的标签仍保持语义,不会退化为<div>
第三方 UI 库组件内部用了 div,怎么补语义?
像 Element Plus 的 <el-card>、Ant Design Vue 的 <a-card> 默认用 <div> 实现,无法直接替换成 <article>。这时得靠 ARIA 补救:
<el-card aria-roledescription="article" role="region" aria-labelledby="card-title"> <h2 id="card-title" slot="header">用户须知</h2> <p>这里是正文...</p> </el-card>
关键不是强行改标签,而是明确传达意图:
-
role="region"配合aria-roledescription让屏幕阅读器读作 “article” -
aria-labelledby关联标题,替代原生<article>的隐式关联 - 避免滥用
role="article"—— WAI-ARIA 规范不鼓励覆盖原生语义标签,仅当无法修改底层 DOM 时才用此兜底
真正要警惕的是:把语义标签当成“样式开关”来用,比如只为了 margin/padding 就套个 <aside>。它本质是内容关系声明,不是 CSS 类别。











