语义化标签是可维护性底线,非加分项:唯一且不嵌套,表独立可分发内容,须配标题,仅用于相关旁注;滥用套娃导致seo降权、无障碍失效、dom查询失稳。

不改语义结构,只调样式或加 JS,页面迟早变成“改一处崩三处”的泥潭。 语义化不是让代码“看起来更规范”,而是让 document.querySelector('main') 能稳稳拿到主体、让 axe 工具不报无障碍错误、让新同事扫一眼就能分清哪块是导航哪块是文章——这是可维护性的底线,不是加分项。
为什么 <div> 套 <code><div> 是可维护性杀手
<p>当 HTML 里全是 <code>class="container-v2"、class="header-fix-2024"、class="box-wrapper" 时,没人能靠源码判断出哪个区块该被 SEO 抓取、哪个是独立文章、哪个该被屏幕阅读器跳过。开发者必须来回切 CSS、查 JS 绑定、翻设计稿才能确认作用域——这不是写代码,是在考古。
- 类名易冲突、易过时、不敢删:同一页面出现
class="nav-active" 和 class="nav-new" 是常态
- DOM 查询不稳定:
document.querySelector('.content') 可能命中侧边栏或弹窗里的同名 class
- SEO 信号丢失:Googlebot 不解析 class 名,它只认
<main></main>、<article></article> 这类原生结构
- 无障碍失效:屏幕阅读器无法从
<div role="navigation"> 确信这就是导航,但遇到 <code><nav></nav> 就会直接提供跳转快捷键
<main></main>、<section></section>、<article></article> 到底怎么选不踩坑
选错标签比不用还糟。把商品列表塞进 <aside></aside>,等于告诉辅助技术和搜索引擎“这段内容不重要”,SEO 会降权,视障用户也很难定位。
-
<main></main> 每页只能有一个,且不能嵌套在 <header></header>、<footer></footer>、<nav></nav> 或另一个 <main></main> 内部
-
<article></article> 表示独立、可分发的内容(如一篇博客、一条新闻),可嵌套自己的 <header></header> 和 <footer></footer>
-
<section></section> 必须有明确主题,且建议配一个 <h2></h2>~<h6></h6>;纯视觉分隔不用它,比如“右边那个 div”不是 <section></section> 的使用场景
-
<aside></aside> 只用于与主内容相关但可独立存在的信息(如作者简介、侧边推荐),不是“所有非主要内容都往里塞”
用 data-module 替代 class 做模块锚点
靠 class 名做 JS 查询或 CI 校验,本质是把语义逻辑耦合进样式层。一旦设计师改个色、前端换套组件库,class="btn-primary" 可能还在,但功能早已不是“主按钮”了。
- 给每个模块根元素加
data-module="header"、data-module="product-list",再配 data-version="1.3"
- JS 查询统一用
document.querySelectorAll('[data-module="header"]'),比 .querySelector('.header') 更可靠
- 别用
id 做模块标识:循环渲染商品卡片时,id="product-item" 会重复,document.getElementById() 只返回第一个
- Chrome DevTools → Elements → 右键节点 → “Break on” → “Attribute modifications” 可快速暴露冗余包裹层
嵌套超过三层就该警觉:<div><div><div><p> 这种结构,连审查元素都要点四下才能定位到目标文本节点。DOM 树过深不仅拖慢渲染,更让维护成本指数上升——真正的复杂点不在 JS 逻辑里,而在你每次想改个页脚样式,却得先花五分钟搞清它到底被几个 <code><div> 包着。 </div>
class="nav-active" 和 class="nav-new" 是常态document.querySelector('.content') 可能命中侧边栏或弹窗里的同名 class<main></main>、<article></article> 这类原生结构<div role="navigation"> 确信这就是导航,但遇到 <code><nav></nav> 就会直接提供跳转快捷键
<main></main>、<section></section>、<article></article> 到底怎么选不踩坑
选错标签比不用还糟。把商品列表塞进 <aside></aside>,等于告诉辅助技术和搜索引擎“这段内容不重要”,SEO 会降权,视障用户也很难定位。
-
<main></main>每页只能有一个,且不能嵌套在<header></header>、<footer></footer>、<nav></nav>或另一个<main></main>内部 -
<article></article>表示独立、可分发的内容(如一篇博客、一条新闻),可嵌套自己的<header></header>和<footer></footer> -
<section></section>必须有明确主题,且建议配一个<h2></h2>~<h6></h6>;纯视觉分隔不用它,比如“右边那个 div”不是<section></section>的使用场景 -
<aside></aside>只用于与主内容相关但可独立存在的信息(如作者简介、侧边推荐),不是“所有非主要内容都往里塞”
用 data-module 替代 class 做模块锚点
靠 class 名做 JS 查询或 CI 校验,本质是把语义逻辑耦合进样式层。一旦设计师改个色、前端换套组件库,class="btn-primary" 可能还在,但功能早已不是“主按钮”了。
- 给每个模块根元素加
data-module="header"、data-module="product-list",再配data-version="1.3" - JS 查询统一用
document.querySelectorAll('[data-module="header"]'),比.querySelector('.header')更可靠 - 别用
id做模块标识:循环渲染商品卡片时,id="product-item"会重复,document.getElementById()只返回第一个 - Chrome DevTools → Elements → 右键节点 → “Break on” → “Attribute modifications” 可快速暴露冗余包裹层
嵌套超过三层就该警觉:<div><div><div><p> 这种结构,连审查元素都要点四下才能定位到目标文本节点。DOM 树过深不仅拖慢渲染,更让维护成本指数上升——真正的复杂点不在 JS 逻辑里,而在你每次想改个页脚样式,却得先花五分钟搞清它到底被几个 <code><div> 包着。 </div>











