根容器必须静态唯一且在index.html中硬编码存在,不可动态创建或销毁,需留空、显式设置min-height:100vh,并确保id在html与js中严格一致。

根容器必须是静态且唯一
SPA 的根容器不是可选的“最佳实践”,而是运行前提:浏览器无论访问 /、/user/123 还是 /settings,都得把内容塞进同一个 DOM 节点里。这意味着你不能写多个 HTML 文件,也不能在 JS 里反复创建/销毁 <main></main> 或 <div id="app">——它得在 <code>index.html 中硬编码存在,且生命周期贯穿整个应用。
常见错误是用 JS 动态生成根容器,比如:
document.body.innerHTML = '<div id="app"></div>';
这会导致首次渲染后所有事件监听、CSS 作用域、第三方库挂载点全部失效。正确做法只有一处声明:
<main id="app"></main><script src="app.js"></script>
-
id="app"不是必须叫这个名,但必须全局唯一、不可重复、不被 JS 删除或替换 - 该节点不能设为
display: none或visibility: hidden,否则部分动画库或滚动逻辑会误判尺寸 - 避免把它放在
<template></template>或<noscript></noscript>里——这些标签的内容默认不参与渲染树
容器内不预埋业务 HTML 内容
根容器里什么也不该有,除了空壳结构。任何实际页面内容(比如“欢迎页文案”“导航栏 HTML 片段”)都必须由 JS 动态注入。否则会出现两个问题:一是 SEO 抓取时看到的是静态占位内容而非真实路由对应视图;二是服务端 fallback 返回 index.html 后,用户直接访问 /dashboard 却看到首页内容,造成状态错乱。
错误示例:
<main id="app"><h1>首页</h1> <p>这是首页描述</p> </main>
正确写法就是留空:
使用 Puppeteer + Chrome 将 HTML 渲染为中文 PDF,自动处理图表等待、Tab 展开、动画、测高、白边消除、防分页,适用于看板、报表、网页和交互图表转 PDF。
<main id="app"></main>
- 若需加载骨架屏(skeleton),应通过 CSS 隐藏 + JS 控制显隐,而不是写死 HTML
- 不要用
<iframe></iframe>替代根容器——它隔离了 JS 上下文和 history API,无法响应popstate - 如果用 Web Components,自定义元素必须挂载在根容器内部,不能替代它
容器尺寸与布局需主动接管
浏览器默认不会为一个空的 <main id="app"></main> 分配高度,尤其在 flex/grid 布局中容易塌陷。这不是样式问题,而是 SPA 必须显式声明“这里要撑满视口”。否则滚动、动画、第三方图表库都会出偏移或渲染异常。
最简可靠方案是在 CSS 中固定根容器高度:
html, body { height: 100%; margin: 0; }
#app { min-height: 100vh; }
- 用
min-height: 100vh而非height: 100vh,防止内容超长时被截断 - 避免在 JS 中用
clientHeight计算后再设置 style.height——DOM 尚未渲染完成,值为 0 - 如果使用 CSS-in-JS 或主题切换,确保根容器的尺寸规则始终优先于子组件覆盖
容器 ID 与 JS 引用必须严格一致
看似 trivial,但线上高频报错源于 ID 拼写差异或大小写混用。JS 里写的 document.getElementById('App') 和 HTML 里的 id="app" 不匹配,会导致整个渲染链路静默失败——没报错,但内容不出现。
检查要点:
- HTML 中的
id值全小写,无空格、无下划线(如id="root"可,id="my-app"不可,因getElementById不支持连字符解析) - JS 中引用时必须完全一致,区分大小写:
document.getElementById('App')≠document.getElementById('app') - 不要依赖 jQuery 的
$()或现代选择器如querySelector('#app')来绕过这个问题——它们同样敏感,且增加额外依赖
真正容易被忽略的,是构建工具(如 Vite、Webpack)在 HTML 注入阶段自动修改 ID 的行为。某些插件会重写 id="app" 为带哈希的版本,却没同步更新 JS 中的查找逻辑——这种问题只在 build 后暴露,开发时一切正常。










