把普通网页的按钮、边框和文字段落直接变成 2D 平台跳跃游戏的地形,甚至利用拖拽浏览器窗口引发的页面重排把角色弹飞——近期在开发者社区流传的交互式网页项目 Walker Playground(页面标题为 Lemmings CSS Animation),用一套精巧的 DOM 几何碰撞规则复刻了经典游戏《疯狂小旅鼠》(Lemmings)。这个项目最核心的工程价值,在于它撕掉了纯 CSS 动画的标签误区,展示了如何将浏览器排版引擎里原本被视为性能开销的页面重排(Reflow),反向改造成实时物理动量。

打开该演示页面,用户只需点击按钮或在控制台调用 __walker.add(),就能在网页里生成自主行走的像素小人。与传统内嵌在 Canvas 画布里的网页小游戏不同,这些小人直接踩在真实的 HTML 元素上。你可以用鼠标拖拽它们,或者轻拂将其抛向高处的卡片;当页面存在多列文本或自适应卡片时,快速缩放浏览器窗口触发换行,站在元素表面的小人会顺着排版突变的位移被直接弹射出去。

标题写着 CSS 动画,底子却是 JavaScript 逐帧物理仿真

很多初级开发者初看标题 Lemmings CSS Animation,容易误以为现代 CSS 已经强大到能独立处理 DOM 边界碰撞与抛物线弹射。这是一个典型的技术认知错位。

CSS 只是视觉画皮,JavaScript 才是驱动物理世界的骨骼(剖面示意)
CSS 只是视觉画皮,JavaScript 才是驱动物理世界的骨骼(剖面示意)

在前端领域,早就有开发者做过真正的纯 CSS 旅鼠演示。例如开发者 Joan León 曾用 box-shadow 绘制像素小人,配合 CSS keyframes 和 step-start 属性,在 8 个离散帧之间循环切换。但那种方案本质上只是预设序列的精灵图动画(Sprite Animation),小人只能在固定轨道上机械迈步,对周围的网页元素毫无感知。

预设脚本动画与实时交互仿真的架构边界 纯 CSS 预设动画 (Joan León 方案) 渲染方式:box-shadow 像素绘制 驱动核心:Keyframes + 8 帧 step-start 环境感知:无地形与碰撞逻辑 局限于固定序列,无法响应交互 JS + CSS 混合仿真 (Walker Playground) 渲染方式:CSS 负责步态周期与 transform 驱动核心:requestAnimationFrame 逐帧计算 环境感知:实时读取 DOM 几何边界 支持拖拽抛掷与窗口重排动量传递

CSS 的关键帧模型天生缺乏状态记忆与空间计算能力。要在网页里实现重力下落、墙壁阻挡以及窗口缩放时的动量传递,底层必须依赖 JavaScript 的 requestAnimationFrame() 接口。系统需要在每一帧获取时间戳,实时读取页面元素的几何包围盒,计算小人的位置、速度矢量与碰撞结果,再将坐标更新到视图上。

Walker Playground 真正采用的是行为与视觉解耦的混合架构。JavaScript 充当幕后的小型物理引擎,接管所有空间决策与状态机;CSS 则退居渲染层,只负责角色行走周期的步态帧切换,并通过修改 transform 和 opacity 属性来移动角色,从而避开昂贵的图层重绘开销。

标题里的 CSS 只是视觉画皮,JavaScript 才是驱动物理世界的骨骼。

为什么文字段落必须做成单向穿透地板

把现有的 DOM 树直接当成游戏关卡,最棘手的不是怎么让小人动起来,而是如何处理网页排版与刚体物理之间的冲突。如果开发者简单粗暴地把页面上所有 HTML 标签的包围盒都设为实心墙体,小人只要走进一段普通文本,就会立刻陷入死锁。

实心边框阻挡去路,单向文字踏板容许角色自由穿梭(示意图)
实心边框阻挡去路,单向文字踏板容许角色自由穿梭(示意图)

原因出在网页排版的默认几何尺度上。在常规正文中,两行文字之间的行距(Line-height)往往小于像素小人的身高。如果每一行文字都是上下左右全封闭的实心碰撞体,小人从上一行末尾掉到下一行时,头部就会被上一行的底边死死卡住,既走不动也掉不下去。

DOM 元素的双层碰撞规则设计 全实心刚体层 涵盖元素:边框 (Borders) / 卡片盒子 / 按钮 (Buttons) / 图片 / 表单字段 物理规则:四面完全阻挡,角色可沿顶边行走,掉入闭合边框内部会被困住 单向穿透平台层 涵盖元素:文章段落中的每一行独立文本 (Text Lines) / 页面底部兜底长地板 物理规则:仅顶部承重可站立、短行末端可跌落;水平方向完全可穿透,防行间卡死

为了解决这个排版死结,该项目对 DOM 元素做了极有巧思的分类处理。卡片边框、按钮、图片和表单输入框被设定为全实心碰撞体,小人撞上侧面会掉头,掉进封闭边框里会被关住;而文本段落里的每一行字,都被单独拆解为单向穿透地板。

在这种规则下,文字行只在垂直下落方向提供支撑力。小人可以稳稳站在字行顶部,走到短句末尾时顺势跌落到下一行;但在水平行走或从下方跃起时,字行不会产生任何横向阻挡。这种取舍让小人得以在密集的多列文章段落里自由穿梭,最后由页面最底部预设的一条通栏长地板兜住所有坠落到底的角色。

把性能毒药变成核心玩法:给前端开发者的启示

在常规的 Web 性能工程里,浏览器的布局重排(Layout Reflow)一直是开发者极力规避的性能毒药。每当窗口尺寸改变导致 Flex 或 Grid 容器里的卡片换行、多列文本重新流式分布时,浏览器都要重新计算成百上千个节点的几何位置。

页面重排能将角色弹射升空,但节点过多也会压垮帧率(示意图)
页面重排能将角色弹射升空,但节点过多也会压垮帧率(示意图)

Walker Playground 反其道而行之,直接把排版引擎的重排过程当成了物理引擎的动力源。当用户快速拖拽缩放浏览器窗口时,卡片换行或字行重排会导致小人脚下的支撑面发生瞬时位移;系统捕捉到前后两帧之间 DOM 节点边界的剧烈坐标差,将其折算成施加给小人的加速度与初速度,从而实现了窗口缩放弹射(Resize Launch)的独特交互。

  • 结论.对于前端开发者与交互设计师而言,这个项目证明了构建轻量级网页物理交互未必需要引入庞大的 WebGL 或 Canvas 游戏引擎,直接榨干原生 DOM 的几何测量接口就能做出极具生命力的创意实验。

不过,这种直接拿 DOM 当物理地形的做法也有明显的工程边界。目前公开代码库中尚未找到包含 __walker.add() 接口的已验证开源仓库(GitHub 上同名的 dynamicmobility/walker-playground 实为步行模型仿真研究,与该项目无关)。如果开发者想在生产环境的个人博客或营销落地页复刻类似效果,最大的瓶颈在于高频读取 DOM 布局信息引发的强制同步布局(Layout Thrashing)——一旦页面节点过多或同屏小人数量失控,帧率就会迅速崩盘。接下来值得观察的是,该项目的作者是否会正式开源底层碰撞代码,以及现代 CSS 正在推进的锚点定位(Anchor Positioning)等新特性,未来能在多大程度上帮 JavaScript 分担这类空间位置追踪的计算压力。