如何使用HTML和ResizeObserver监听元素尺寸变化?
- 内容介绍
- 文章标签
- 相关推荐
本文共计900个文字,预计阅读时间需要4分钟。
它只响应元素+content-box+尺寸的变化,也就是宽高(不含+padding+、+border+、+margin+)。例如:
常见误判场景:
• 元素被父容器 overflow: hidden 截断,自身没变,但“可见区域”变了 → ResizeObserver 不管这个
• 使用 transform: scale() 视觉上放大 → 实际 layout 尺寸未变 → 不触发
• visibility: hidden 或 opacity: 0 → 元素仍在文档流且尺寸未变 → 不触发
怎么正确创建和使用 ResizeObserver 实例
必须用 new ResizeObserver() 构造,回调函数接收两个参数:entries(ResizeObserverEntry 数组)和 observer(当前实例)。每个 entry 的 contentRect 是核心数据源,含 width/height/top/left 等只读属性。
- 务必在观察前先确保目标元素已挂载到 DOM,否则
observe()会静默失败 - 一个
ResizeObserver实例可观察多个元素,但所有回调共用同一个队列,避免在回调里再同步调用observe()或unobserve(),否则可能漏触发 - 如果需监听子元素尺寸(如内部滚动容器),直接
observe(childEl)即可,无需嵌套 observer
简单示例:
立即学习“前端免费学习笔记(深入)”;
const ro = new ResizeObserver(entries => { for (const entry of entries) { console.log(entry.contentRect.width, entry.contentRect.height); } }); ro.observe(document.querySelector('#my-box'));
为什么 ResizeObserver 回调有时不执行或延迟执行
它基于浏览器 layout 后的异步队列,不是实时事件,所以有微小延迟(通常 1–2 帧)。更关键的是:如果目标元素被移出 DOM(例如 Vue/React 组件卸载)、或 CSS 设为 display: none,浏览器会自动停止观察,且不会触发回调 —— 这不是 bug,是规范行为。
- React/Vue 中组件销毁前,必须手动调用
ro.unobserve(el)或ro.disconnect(),否则可能内存泄漏 - 动态插入元素后,要重新
observe(),不能依赖“之前观察过父容器就自动覆盖子元素” - 某些旧版 Safari(≤15.4)对
contentRect的top/left返回 0,仅width/height可靠;若需位置,建议搭配getBoundingClientRect()补充
替代方案对比:window.addEventListener('resize') vs ResizeObserver
window.resize 只能监听整个视口,无法感知单个元素变化,且高频触发(尤其拖拽窗口时),容易卡顿。而 ResizeObserver 是按需驱动、自动节流、精准到元素粒度。
- 不要用
resize监听某个 div —— 它根本收不到 - 也不要用
setInterval+offsetWidth轮询 —— 性能差、不准、干扰 layout - IE 完全不支持
ResizeObserver,如需兼容,可用 polyfill,但注意 polyfill 依赖scroll或animation模拟,对transform或opacity类变化无效
真正需要关注的边界点:当元素尺寸由 CSS 动画驱动(如 max-height 过渡)时,ResizeObserver 只会在动画关键帧结束时报告最终值,中间过程不可见 —— 这不是缺陷,是浏览器 layout 机制决定的。
本文共计900个文字,预计阅读时间需要4分钟。
它只响应元素+content-box+尺寸的变化,也就是宽高(不含+padding+、+border+、+margin+)。例如:
常见误判场景:
• 元素被父容器 overflow: hidden 截断,自身没变,但“可见区域”变了 → ResizeObserver 不管这个
• 使用 transform: scale() 视觉上放大 → 实际 layout 尺寸未变 → 不触发
• visibility: hidden 或 opacity: 0 → 元素仍在文档流且尺寸未变 → 不触发
怎么正确创建和使用 ResizeObserver 实例
必须用 new ResizeObserver() 构造,回调函数接收两个参数:entries(ResizeObserverEntry 数组)和 observer(当前实例)。每个 entry 的 contentRect 是核心数据源,含 width/height/top/left 等只读属性。
- 务必在观察前先确保目标元素已挂载到 DOM,否则
observe()会静默失败 - 一个
ResizeObserver实例可观察多个元素,但所有回调共用同一个队列,避免在回调里再同步调用observe()或unobserve(),否则可能漏触发 - 如果需监听子元素尺寸(如内部滚动容器),直接
observe(childEl)即可,无需嵌套 observer
简单示例:
立即学习“前端免费学习笔记(深入)”;
const ro = new ResizeObserver(entries => { for (const entry of entries) { console.log(entry.contentRect.width, entry.contentRect.height); } }); ro.observe(document.querySelector('#my-box'));
为什么 ResizeObserver 回调有时不执行或延迟执行
它基于浏览器 layout 后的异步队列,不是实时事件,所以有微小延迟(通常 1–2 帧)。更关键的是:如果目标元素被移出 DOM(例如 Vue/React 组件卸载)、或 CSS 设为 display: none,浏览器会自动停止观察,且不会触发回调 —— 这不是 bug,是规范行为。
- React/Vue 中组件销毁前,必须手动调用
ro.unobserve(el)或ro.disconnect(),否则可能内存泄漏 - 动态插入元素后,要重新
observe(),不能依赖“之前观察过父容器就自动覆盖子元素” - 某些旧版 Safari(≤15.4)对
contentRect的top/left返回 0,仅width/height可靠;若需位置,建议搭配getBoundingClientRect()补充
替代方案对比:window.addEventListener('resize') vs ResizeObserver
window.resize 只能监听整个视口,无法感知单个元素变化,且高频触发(尤其拖拽窗口时),容易卡顿。而 ResizeObserver 是按需驱动、自动节流、精准到元素粒度。
- 不要用
resize监听某个 div —— 它根本收不到 - 也不要用
setInterval+offsetWidth轮询 —— 性能差、不准、干扰 layout - IE 完全不支持
ResizeObserver,如需兼容,可用 polyfill,但注意 polyfill 依赖scroll或animation模拟,对transform或opacity类变化无效
真正需要关注的边界点:当元素尺寸由 CSS 动画驱动(如 max-height 过渡)时,ResizeObserver 只会在动画关键帧结束时报告最终值,中间过程不可见 —— 这不是缺陷,是浏览器 layout 机制决定的。

