做抽屉菜单的人,谁没写过一套 touchstart/touchmove 手势判断——今天 HTML 两个属性把边缘滑动这件事彻底原生化了
做移动端抽屉菜单的人,几乎都写过同一套东西:监听 touchstart 记起点、touchmove 算位移、跟一个阈值比大小、超过了才 transform 把菜单滑出来,松手再判断是回弹还是停住。这套手势判断写了十几年,每个项目都要抄一遍,还总在 iOS 和安卓上手感不一致。今天浏览器准备把这件事收回去自己做——两个 HTML 属性加一个命令值,抽屉菜单不用一行 JavaScript 就能滑出来了。
这次到底多了什么
Open UI 提出的 Declarative Overscroll Actions,核心思路一句话:把「滚动到边界之后那块多出来的空间」正式当作一个可用的布局区域,然后用声明式的方式把元素绑上去。
涉及三个东西:
overscrollcontainer:加在容器上,声明「这个容器支持越界区域」overscrollarea:加在容器的一个直接子元素上,标记「这块内容放在越界区里」commandfor+ 三个新命令值:show-overscroll、hide-overscroll、toggle-overscroll
写出来大概长这样:
<div id="container" overscrollcontainer>
<menubar id="menu" overscrollarea>
<menuitem>Home</menuitem>
<menuitem>Settings</menuitem>
</menubar>
Some content.
</div>
<button commandfor="menu" command="toggle-overscroll">Toggle Menu</button>
行为上分两条路径:一是用户把 #container 滚到尽头,滚动顺势「链」到 #menu 上,把它拉进视野——注意这里 #container 本身甚至不需要是个滚动容器;二是点那个按钮,等价于对菜单做一次类似 scrollIntoView 的动作。两条路走的是同一个开关。
为什么这次不是又一个手势库
以前实现同一个效果,绕不开三个坑,这次是逐条对着修的。
第一,手势事件你得自己收一遍。 触摸屏走 touch 事件,触控板走 wheel 事件,键盘又是一套——WICG 在 overscroll 事件的说明里把这点讲得很直白:过去的做法要为每种滚动方式单独实现一遍,而且想在滚动结束的那一刻触发动画,触控板上根本没有可用的事件。现在这些物理过程交给浏览器,合成器线程可以接管,滚动手感是浏览器原生那一套。
第二,无障碍基本是事后补的。 手写的手势菜单,键盘用户按 Enter 是打不开的,读屏软件也念不出这个菜单的存在。新 API 的硬性要求是:必须存在一个语义化的按钮(带 commandfor 的 <button>)来开关这块区域,否则这个结构根本不成立。也就是说,「键盘能开、读屏能念」这件事是被 API 强制保证的,不是靠开发者自觉。
第三,老办法容易和浏览器自己的手势打架。 横向滑动手势在很多浏览器上绑着前进/后退,你做一个横向抽屉,很可能是滑着滑着页面就跳走了。新 API 把这块区域的「模态性」交给浏览器统一管理:越界时会有 ::overscroll-backdrop(一个类似弹层遮罩的伪元素,本身就充当关闭触发器),打开时是惰性的(inert),点它就在轻触关闭的逻辑里,不需要你再拼一套。
落地时要注意的几个细节
如果你打算试,几个点先记住:
toggle-overscroll或show-overscroll必须有一个。 只写overscrollcontainer和overscrollarea,浏览器不会把它当成越界结构——少了那个可激活的触发按钮,整套声明无效。hide-overscroll则是可有可无,因为::overscroll-backdrop已经能关。- 越界区必须是容器的直接子元素。 它通常会被移出正常文档流,效果上像
position: absolute且被容器包含。 - 多个越界区按 LIFO 顺序链。 一个容器可以有多个越界区(左右各一个抽屉),滚动链入时遵循「后进先出」:DOM 顺序里最后一个越界区先被链入、先滚动。
- 这是一次渐进增强。 目前它还在 developer testing 阶段,Chrome 侧是 DevTrial(桌面和安卓 149),需要打开
enable-experimental-web-platform-features这个 flag。生产环境里,老的 JS 手势方案该留还是得留,新 API 当加分项。
现在可以做的三步
- 别急着删老代码。 先去 chrome://flags 打开
enable-experimental-web-platform-features,把手上一个抽屉菜单按上面的结构改一版,跑起来看手感和你现在的实现差多少——尤其是滚动接力那一下的连贯性。 - 回头审你自己的抽屉无障碍。 不管用不用新 API,先检查你的手势菜单有没有一个真的能被键盘触发的按钮、有没有正确处理 inert 和轻触关闭。这两点是新 API 的底线要求,也本来就该是底线。
- 横向手势页面重点排查。 如果页面里有横向滚动区(轮播、图片画廊、时间轴),现在就用
overscroll-behavior-x: contain把它和浏览器的历史前进/后退手势隔开——新 API 普及之前,这是最容易被用户投诉的手感问题。
浏览器把「越界那点空间」从边角料变成一个正经的布局能力,这件事的意义不在于少写几十行手势代码,而在于抽屉这类交互终于有了统一的、自带无障碍兜底的实现路径。
评论区
登录后可评论。