![]()
Safari 26.2版本去年12月发布时,一个看似微小的更新——支持scrollend事件——让前端开发者的群聊里罕见地出现了集体如释重负的表情包。这不是什么炫酷的视觉特效,也不是性能优化,只是一个"滚动结束"的通知信号。
但这个信号,开发者等了整整三年。
一个事件,三种浏览器早就交卷
Chrome 114在2023年5月就支持了。Edge 114同期跟进。Firefox 109更早,2023年1月已经落地。三大浏览器早早达成共识,唯独Safari按兵不动。这种局面下,前端工程师写代码像在玩扫雷——同样的滚动检测逻辑,在苹果设备上必须用setTimeout()打补丁,在其他浏览器上却能原生运行。
WebKit团队的公告写得克制:"a reliable signal that scrolling has finished"。翻译成人话:以前你们用100毫秒、150毫秒的定时器去"猜"滚动有没有停,现在不用猜了。
这个"猜"字背后是多少行脆弱的兜底代码。开发者需要监听scroll事件,然后用debounce(防抖)函数设个延迟,假设用户150毫秒没操作就算滚动结束。问题是,触控屏的惯性滚动、键盘导航、JavaScript调用的scrollTo(),每种场景的停止时机都不一样。定时器设太短,惯性滚动还没完就触发;设太长,用户感觉卡顿。更麻烦的是,不同设备的刷新率、性能差异让这个魔法数字永远调不准。
scrollend事件的本质,是把"推测"变成"订阅"。浏览器内部清楚滚动何时真正停止,现在它愿意告诉开发者了。
为什么偏偏是Safari最后交卷
苹果对Web标准的跟进节奏,向来有自己的算盘。不是不能做,是优先级排期的问题。scrollend事件早在2022年就已进入W3C草案,2023年Baseline(跨浏览器兼容基线) status将其列为"新可用"特性。Baseline的定义很明确:当某个特性被Safari、Chrome、Firefox、Edge全部支持,才算"广泛可用"。
Safari的缺席让Baseline的绿灯迟迟亮不了。对大型前端框架和组件库维护者来说,这意味着要么放弃这个特性,要么写两套代码。很多团队选择了前者——宁可继续用定时器 hack,也不愿维护分支逻辑。
苹果拖延的代价,是整个生态系统的观望。根据Chrome Platform Status的公开数据,scrollend在Chromium系的采用率2023年就超过了60%,但跨框架的polyfill(兼容性代码)下载量直到2024年仍在增长。开发者不信邪,反复确认Safari版本号,然后叹口气把setTimeout塞回去。
这种"等待-妥协-再等待"的循环,在Safari的历史上反复上演。Web Push、WebP、Service Worker,都曾让前端社区经历类似的漫长季节。scrollend的特殊之处在于,它的替代方案虽然丑陋,但确实能跑。不像某些API缺失会直接阻断功能,定时器hack的"可用性"反而降低了苹果的紧迫感。
事件机制背后的设计博弈
scrollend的规范制定并非一帆风顺。W3C的CSSOM View Module草案经历了多轮修订,核心争议在于:什么算"滚动结束"?
用户手指离开屏幕后的惯性滑行,算不算滚动过程?程序调用的平滑滚动(smooth scroll),中间状态要不要暴露?如果滚动被另一个滚动打断,是触发一次还是两次end?这些细节决定了API的实用性。
最终定稿的方案是:无论触发来源,只要滚动动画彻底停止,就触发一次scrollend。惯性滚动、键盘导航、JavaScript调用,全部统一。这个设计牺牲了部分中间状态的可观测性,换取了行为的一致性。
WebKit的实现额外处理了一个边界情况:当滚动容器被隐藏或销毁时,确保事件不会泄露。这种防御式编程反映了Safari团队对内存管理的偏执——也是其渲染引擎长期以来的技术标签。
对开发者而言,迁移成本极低。原有代码结构可以保留,只需把定时器清理逻辑换成事件监听:
```javascript // 以前 let scrollTimeout; element.addEventListener('scroll', () => { clearTimeout(scrollTimeout); scrollTimeout = setTimeout(() => { console.log('猜测滚动结束'); }, 150); }); // 现在 element.addEventListener('scrollend', () => { console.log('确认滚动结束'); }); ```
代码行数差不多,但确定性天差地别。前者是"我觉得停了",后者是"浏览器告诉我停了"。
Baseline完成度:一个被低估的指标
scrollend的补齐让Baseline 2023特性集的完成度达到100%。这个指标由Google、Mozilla、Apple、Microsoft共同维护,本意是给开发者一个"可以放心用"的清单。但清单的权威性取决于最慢的那个成员。
Baseline分两个等级:"新可用"(Newly available)要求四大引擎最新版支持;"广泛可用"(Widely available)需要30个月的稳定期。scrollend现在刚跨过第一道门槛,要到2026年底才能拿到"广泛可用"的认证。
这个30个月的缓冲期,是给小众浏览器和旧版本留的余地。但对实际项目来说,"新可用"已经足够。企业内部的B端系统、面向消费者的C端产品,只要用户画像不是极端老旧设备,都可以开始迁移。
一些头部组件库已经行动。React Spectrum的useScrollEnd hook在Safari 26.2发布后一周就标记为稳定版,移除了polyfill依赖。Vuetify的v-scroll directive下个主版本将默认使用原生事件。这些改动对用户无感知,但维护者的issue列表里少了一类"Safari滚动异常"的幽灵bug。
更深层的影响在性能层面。定时器hack的150毫秒延迟,意味着滚动停止后UI状态更新至少要等这么久。虚拟列表的渲染回收、懒加载图片的触发、滚动位置的记忆恢复,全部卡在这个人为制造的间隙里。scrollend的即时性,让这些场景有了零延迟响应的可能。
苹果的节奏,行业的耐心
Safari 26.2的发布说明里,scrollend被埋在"Web API"分类的第三项,前面是Intersection Observer的改进,后面是CSS嵌套规则的更新。这种排序很苹果——不夸大单个特性,但默默填坑。
对比Chrome的发布博客,同样的事件支持被写成"解决开发者多年痛点"的头条。两种叙事风格,反映了产品定位的差异。Google需要讨好开发者社区,苹果更在意终端用户的感知稳定性。
这种差异也体现在bug修复的响应速度上。scrollend落地后,社区很快发现Safari对嵌套滚动容器的处理与Chrome存在微妙差异:当子容器滚动到底部、触发父容器继续滚动时,事件触发的时序不一致。WebKit的issue tracker里,相关报告在48小时内得到确认,修复排入26.3版本。
这个响应速度,比Service Worker时代的苹果快了不少。是团队扩张的结果,还是内部优先级调整,外界不得而知。但一个可见的趋势是,Safari的技术债务正在系统性偿还。2024年以来,Baseline的"新可用"特性在Safari上的落地间隔,从平均14个月缩短到6个月。
对25-40岁的前端从业者来说,这种变化比任何新框架都实在。不需要重写技术栈,不需要学习新概念,只是删掉几行hack代码,让项目少一分脆弱性。这种"做减法"的升级,在工程成熟度的坐标轴上,比"做加法"更接近本质。
scrollend事件的支持状态,现在可以在caniuse.com上查到完整的绿色格子。这个页面的截图,在过去三年里被无数次贴进技术评审会的PPT,作为"暂缓采用"的论据。现在它终于可以用来证明另一件事:等待是有尽头的。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.