配了三年地图,每次对角线滚动都要靠手感和运气——今天这件事被一个 CSS 属性彻底原生化了
你做地图组件,用户从左上角往右下角划,浏览器直接把手势锁死成垂直滚动。你以为是用户手势有问题,其实是浏览器在替他们做决定。
这就是 scroll axis locking,业界也叫”railing”。大多数时候这是好事——你看文章的时候手腕歪一下,浏览器帮你纠正成纯垂直滚动,阅读体验更顺。但到了地图,白板、360 度全景图这种本身就要求自由二轴滚动的场景,这个”帮助”就变成了限制。
Chrome 153 给你一件 CSS 原生的工具,叫 scroll-axis-lock。
原理:一行声明换掉整个 wheel 监听
scroll-axis-lock 来自 CSS Overflow Level 5 规范,目前 Chrome 153+ 和 Edge 153+ 支持。Firefox 和 Safari 还没跟,但这个属性的设计天然支持渐进增强——不支持的浏览器会直接忽略,什么都不会坏。
它只有两个值:
auto:保持浏览器默认行为,大多数情况下是锁定单轴none:关闭轴锁定,手势向量直接透传
用法简单到离谱:
.map-container {
overflow: auto;
scroll-axis-lock: none;
}
就这一行,不需要任何 JavaScript,不需要 trackpad 事件监听,不需要算 deltaX/deltaY 比例。浏览器 compositor 层直接处理,不占主线程。
真实场景:谁真正需要这个
不是所有滚动都需要关掉轴锁。只有”二维滚动容器”才有区别:
适合开 none 的场景:地图(Google Maps / Leaflet / 室内平面图)、设计画布(Figma web 版,白板工具)、360 度全景图浏览、可缩放数据图表、楼层平面图和座位图。
不需要动的场景:普通文章页面(单轴垂直滚动)、横向轮播图、任何本身只有一维滚动的区域。
一个快速判断方法:你的滚动容器如果需要用户按住 Shift 才能横向滚,那它本质上就是一个需要 none 的 2D 容器,只是现在被 Shift 键临时”越狱”了。
性能差异:JS 方案 vs CSS 原生
之前的变通方案基本长这样:
// 监听 wheel 事件,手动融合 deltaX 和 deltaY
el.addEventListener("wheel", (e) => {
e.preventDefault();
const factor = 0.8;
scrollContainer.scrollLeft += e.deltaX * factor;
scrollContainer.scrollTop += e.deltaY * factor;
}, { passive: false });
这个方案有三个问题:
- 主线程阻塞。wheel 事件跑在主线程,背景有重活的时候滚动就卡
- 输入延迟。JS 算完再同步到 compositor,而 native 滚动是直接走 compositor 线程
- 和其他 CSS 特性冲突。scroll-snap、scroll-driven animations、Intersection Observer 对这种”假滚动”的行为定义会不一致
scroll-axis-lock: none 的融合发生在 compositor 层,完全绕开主线程,上下文切换开销为零。
跨平台行为差异:一个被忽视的坑
在真正支持之前,有一点必须心里有数:railing 行为在不同浏览器和操作系统上本来就不一样。
- iOS Safari(触屏):通常不锁轴
- macOS Safari:严格锁轴
- macOS Chrome:根据版本有差异
- Windows/Linux Chrome:部分锁轴
同一个地图组件,在 iPhone 上对角线滚动顺滑,换到 Mac Safari 就开始卡。这不是 bug,是各平台对”什么是意外抖动”的判断标准不同。
加了 scroll-axis-lock: none 之后,这个差异会消失——所有支持这个属性的浏览器都统一不锁轴。这反而可能是个问题:如果用户习惯了 Mac Safari 的轴锁,地图突然可以自由斜滑,体验反而割裂。
建议:加之前问自己一个问题:这个组件的主要用户场景是 2D 自由探索,还是单轴阅读?如果是前者,原生对角线是体验加分;如果用户大部分时间是在垂直或水平单向滚动,这个改变可能反而干扰。
渐进增强写法
因为 Firefox 和 Safari 还不支持,写的时候建议按渐进增强处理:
/* 先保证基础滚动能用 */
.map-container {
overflow: auto;
}
/* 再针对支持的浏览器关锁 */
@supports (scroll-axis-lock: none) {
.map-container {
scroll-axis-lock: none;
}
}
不支持的浏览器用户拿到默认轴锁,体验不降级。
下一步
如果你现在做地图/画板类组件,可以跑一遍这个检查清单:
- 现有组件有没有用 Shift+滚轮做横向滚动?有的话
scroll-axis-lock: none可以直接替换掉 Shift 提示 - 有没有 wheel 事件监听做滚动融合?可以拆掉,改成 CSS 一行
- 用户反馈里有没有”滚动不跟手”的投诉?特别是 Mac + Safari 组合,先确认是不是 railing 在作怪
- 未来要测 Safari 和 Firefox 支持,看他们跟进之后体验是否需要调整
一句话总结:浏览器终于允许你告诉它——这个容器,请别替用户做主。
评论区
登录后可评论。