<main>必须唯一且为<body>直接子元素,否则破坏可访问性树、触发hydration mismatch、导致focus丢失和事件失效;禁止嵌套于<section><div>等任何元素内。

HTML骨架结构不“稳”,交互就容易断——不是JS写得不好,而是DOM锚点松动、语义缺失、替换逻辑错位导致 focus 丢失、事件监听器失效、第三方插件未重初始化。
为什么必须唯一且不能嵌套
浏览器和辅助技术依赖 <main></main> 作为内容主入口。嵌套或重复会破坏可访问性树,React/Vue hydration 时触发 DOM mismatch 报错,document.querySelector('main') 返回非预期节点,后续所有基于它的交互(如 scrollIntoView、focus())都可能失败。
- 每个页面只允许一个
<main></main>,且必须是的直接子元素 - 禁止写成
<section><main></main></section>或<div id="app"><main></main></div> - SPA 中服务端直出的
<main></main>必须与客户端 hydration 时的结构完全一致,包括 class、data-* 属性、甚至注释位置
骨架屏 DOM 替换时如何保住交互状态
用 innerHTML = '' 清空再拼字符串,等于销毁整个子树:表单输入值清零、滚动位置重置、已绑定的 addEventListener 全丢、IntersectionObserver 实例失活。
- 真实内容加载完成时,用
template.replaceWith(realNode)替换整块,保留父容器上的事件监听和属性 - 骨架项与真实项的 class 名、
data-id、层级深度、同级元素数量必须严格一致(哪怕只是多一个空<!-- -->注释) - 页尾无限滚动触发器(如
<div id="infinite-trigger"></div>)必须独立于骨架列表之外,否则 IntersectionObserver 会因骨架动画反复触发回调
lang 和 charset 错位会静默破坏交互链路
lang="zh" 或 lang="zh_CN" 看似无害,实则让屏幕阅读器切换发音规则、拼写检查器匹配错误词库;<meta charset> 写在 <title> 后面,中文乱码会导致 JS 字符串解析失败,document.title = '用户中心' 变成 'û¼',进而让路由守卫或埋点逻辑误判。
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
立即学习“前端免费学习笔记(深入)”;
-
lang值必须符合 BCP 47:简体中文写zh-CN,繁体写zh-TW,局部英文内容用<p lang="en">API response</p> -
<meta charset="UTF-8">必须紧贴<head>开头,前面不能有任何字符(含 BOM、空格、注释),VS Code 右下角确认编码为 “UTF-8” 而非 “UTF-8 with BOM” - SSR 场景下,服务端输出的
lang和charset必须与客户端 hydration 完全一致,否则 React 会报Text content does not match
语义标签缺失会让 focus 和键盘导航失效
纯 <div class="card"> 没有语义,Tab 键跳过它,screen reader 不读它,document.activeElement 永远不会指向它——所有依赖焦点的交互(如模态框关闭、快捷键响应)都卡死。
- 用
<article>包裹独立内容单元(如新闻卡片),用<section>包裹有标题的逻辑区块(需含<h2>~<h6>) -
<nav>只包裹导航链接,logo 和搜索框不属于它;<aside>仅用于与当前内容相关但可独立存在的补充信息(如作者简介、引用) - Chrome DevTools 的 Accessibility 面板中,若
<main>显示No accessible name,说明缺少<h1>或未设aria-labelledby
真正难的不是写出能跑的 HTML,而是让每个标签在 JS 执行前就具备稳定的语义锚点、尺寸占位和 DOM 位置——骨架塌了,后面所有交互都得重搭。


















