body 标签的 onresize 事件基本无效,应改用 window.addEventListener('resize', ...) 并配合节流与 requestAnimationFrame;真正需响应容器变化时优先使用 ResizeObserver;CSS 媒体查询和弹性布局应优先于 JS 监听。

body 标签的 onresize 事件基本无效,别用它做响应式开发。 它不触发、不可靠、不兼容现代框架,强行绑定反而掩盖真正该解决的问题。
为什么 body.onresize 几乎从不工作
浏览器规范里,onresize 事件只对 window 对象原生支持;<body onresize="..."> 在绝大多数浏览器中根本不会触发——不是你写错了,是它本来就不该存在。实测 Chrome/Firefox/Safari 均无视该属性,连控制台警告都不会报。有人看到“偶尔生效”,大概率是误把 window.onresize 的行为归到了 body 上。
想监听窗口变化?只用 window.addEventListener('resize', ...)
这是唯一稳定、可解绑、符合标准的做法:
- 必须加节流:直接在回调里调用
echarts.resize()或重算布局,拖动窗口时会每秒触发 30+ 次,UI 瞬间卡死 - 推荐节流延迟 120–250ms,且包裹
requestAnimationFrame,避免强制同步重排 - 首次加载也要手动触发一次(比如调用
handleResize()),否则页面初始化时不响应 - Vue/React 中务必在组件卸载时调用
removeEventListener,否则内存泄漏 + 多个 handler 冲突
真正该响应的,往往不是窗口尺寸
很多场景下,你其实并不关心 window.innerWidth 变没变,而是某个容器自己撑开了或收窄了:
使用 Puppeteer + Chrome 将 HTML 渲染为中文 PDF,自动处理图表等待、Tab 展开、动画、测高、白边消除、防分页,适用于看板、报表、网页和交互图表转 PDF。
立即学习“前端免费学习笔记(深入)”;
- 侧边栏折叠后主内容区宽度变化
- 卡片内文本增长导致高度突变
- Tabs 切换后面板内容高度不同
这些变化 resize 事件完全感知不到。此时应改用 ResizeObserver,它监听的是元素自身 content-box 的尺寸变化,且天生节流、无需手动清理:
const ro = new ResizeObserver(entries => {
for (const entry of entries) {
const { contentRect } = entry;
console.log(contentRect.width, contentRect.height);
}
});
ro.observe(document.getElementById('main-panel'));
响应式开发的优先级顺序
JS 监听 resize 是最后手段,不是第一选择:
- 先确保
<meta name="viewport" content="width=device-width, initial-scale=1.0">存在且正确 - 能用 CSS 媒体查询解决的,绝不 JS 控制:比如
@media (max-width: 768px) { .nav { flex-direction: column; } } - 能用 CSS 弹性单位(
vw、rem、flex、grid)实现的自适应,就别算像素再设 style - 只有当业务逻辑强依赖尺寸数值(如图表缩放、Canvas 重绘、第三方库强制 resize)时,才上 JS 监听
容易被忽略的一点:resize 触发时,DOM 布局尚未完成,getBoundingClientRect() 返回的可能是旧值;真要精确测量,得等 requestAnimationFrame 下一帧,或者用 ResizeObserver 直接拿 contentRect。


















