问题背景
在 QQ 浏览器最新版(内核 Chromium 123.0.6312.124)中,监听 window resize 事件时,发现在没有手动拖拽窗口的情况下,切换页面路由或操作 DOM 时,resize 事件被意外触发。
复现条件
- 浏览器:QQ 浏览器(21.1.8539.400 64位),Chromium 123 内核
- 操作系统:Windows
- 必要条件:开启 QQ 浏览器左侧边栏(关闭侧边栏则不复现)
- 触发操作:切换路由或进行 DOM 增删
排查过程
第一步:初步怀疑滚动条
resize 事件触发时,clientWidth 变化有时是 10px,接近滚动条宽度,初步怀疑是 DOM 切换导致滚动条出现/消失,挤压了页面宽度。
但有时变化只有 1px,且关闭侧边栏后问题完全消失,滚动条假说无法解释全部现象。
第二步:扩大观测范围
在 resize 回调中同时打印多个宽度指标:
观测结果:
关键发现:innerWidth 也在变化。
innerWidth 是视口宽度,不受页面内容、滚动条影响。它发生变化意味着问题根源在浏览器 UI 层,而非页面本身。
第三步:排除 sub-pixel 取整
怀疑侧边栏导致视口宽度为非整数,布局取整产生 1px 误差。执行验证:
两者均为整数,排除 sub-pixel 取整的可能。
第四步:确认抖动为来回变化
持续监听 innerWidth,触发一次 DOM 切换后,观察到变化序列为:
视口宽度短暂变化后弹回原值,确认是抖动行为。
根本原因
QQ 浏览器左侧边栏在开启状态下,页面 DOM 发生变化时,侧边栏会重新进行布局计算,导致自身宽度出现短暂的 1px 或 10px 变化,从而挤压页面视口宽度,触发真实的 resize 事件。抖动结束后视口宽度弹回原值。
这是 QQ 浏览器自身 UI 层的 bug,与页面代码无关,无法从网页侧阻止事件触发。
解决方案
利用"抖动会弹回原值、且幅度极小"的特性,用防抖 + 阈值两层过滤屏蔽噪声:
两层过滤的分工:
各场景表现:
结论
遇到 resize 事件异常触发时,首先通过同时观测 innerWidth 和 clientWidth 来判断问题根源:
- 只有
clientWidth变化 → 页面内部问题(滚动条、布局) innerWidth也变化 → 浏览器 UI 层问题,页面侧只能做防御性过滤
对于无法修复的浏览器兼容性问题,防抖 + 阈值是通用的防御手段。
