语义标签必须正确使用且与嵌套深度协同检查,否则导致结构空、landmark失效、分块错位;需用语义元素替代div,确保section含标题、main为body直子,避免深层嵌套与冗余包裹,列表用ul/ol,批量dom操作用documentfragment,html分块须依赖真实标题层级。

语义标签必须用对,不能只图写得快
浏览器和屏幕阅读器不认 class 名,只认 <header></header>、<nav></nav>、<main></main>、<section></section> 这些标签的隐含含义。用一堆 <div> 堆出“导航栏”或“文章主体”,结构上就是空的。
<p><code><section></section> 不是 <div> 的高级替代品——它要求内部至少有一个 <code><h1></h1>–<h6></h6>,否则语义失效;<main></main> 必须是 的直接子元素,嵌在 <section></section> 或 <article></article> 里会破坏 landmark 结构。
- 检查 Chrome DevTools → Elements → Accessibility → Landmarks,看是否识别出预期区域
- 用 WebStorm 的 Structure 面板或 VS Code 的 Outline 视图快速定位语义断层
- 避免把
<aside></aside>当作“右侧边栏容器”滥用——它只适用于与主内容相关但可独立存在的旁注类内容
嵌套超过三层就该警觉了
DOM 深层嵌套(比如 div > div > div > div)会让 querySelector 变慢、CSS 选择器匹配变卡、屏幕阅读器遍历变吃力。这不是理论问题,是真实性能拐点。
单个容器下子节点超 50 个时,重排开销陡增;连续两个 <div class="wrapper"><div class="inner"> 是典型冗余包裹。
<ul>
<li>运行 <code>document.querySelectorAll('div > div > div > div'),若返回非空结果,说明存在未收敛嵌套
<ol></ol>/<ul></ul> + <li>,不是 <div> 块堆叠
<h3>动态插入大量内容时,别直接 appendChild</h3>
<p>逐个调用 <code>appendChild 会触发多次重排,尤其在循环中拼 DOM。哪怕只有 20 条数据,肉眼就能感知卡顿。
DocumentFragment 是轻量级离线 DOM 容器,所有节点先挂到它上面,最后一次性挂载到真实 DOM,能规避中间渲染开销。
- 不要写:
for (item of list) { container.appendChild(createItem(item)); } - 要写:
const frag = document.createDocumentFragment(); list.forEach(item => frag.appendChild(createItem(item))); container.appendChild(frag); - 如果用框架(React/Vue),注意 SSR 渲染后 hydration 阶段的 DOM 差异——HTMLHeaderTextSplitter 解析的是静态 HTML,不处理 JS 动态注入内容
长文档分块不能只靠 split_text()
纯按字符切 HTML(如 split_text(chunk_size=500))极易把标题截断在块中间,导致上下文丢失、检索错乱。
HTMLHeaderTextSplitter 的核心价值在于用标题层级当锚点,但前提是标题标签真实存在且嵌套合理。它不执行 JS,所以 Next.js/Remix 等客户端 hydration 页面需先服务端吐出完整 HTML。
- 设置
headers_to_split_on = [("h2", "section"), ("h3", "subsection")],确保每个块携带父级标题路径 - 先用 HTMLHeaderTextSplitter 做粗粒度分割,再用
RecursiveCharacterTextSplitter控制最终长度 - 验证:打开生成的块,确认
<h2></h2>没被切开,且其后所有<p></p>、<ul></ul>都归属正确
<section></section> 却没补标题,或删了两层 <div> 却没同步调整 CSS 选择器,结果样式崩、landmark 失效、分块错位,三件事一块儿发生。</div>











