页面左半边钉着一张地图,右半边是活动详情:标题、时间、地点、三段正文和一块深色的流程表。往下滚,地图上会有一条线从起点开始一段段被画出来,同时地图跟着线的走向平移——始终把正在画的那一点保持在画面中央,就像有人拿着笔在纸上画,而纸在跟着笔动。中途镜头还会短暂推近再退回,像是在强调某一段路线。读完右侧文案,点“展开地图”,地图会平滑铺满整屏并把路线一次画完,右下角出现收起按钮。
这套结构解决的是活动页的一个老问题:路线信息用静态图讲不清楚,用嵌入式地图又太重且不好控制样式。这里的地图只是一张图加一条 SVG 路径,样式完全自己说了算,还不需要任何地图服务的接口。
这套滚动地图的四个组成
路线是一条 SVG 路径,按滚动进度逐段显形。用描边绘制插件把路径的可见区间从零推到全长,进度绑定滚动,往回滚线就往回收。
镜头跟随靠运动路径反向平移。一个圆点沿路径运动,脚本每帧读取它的坐标,把地图整体平移到该坐标的相反方向,于是点永远停在画面中心。
跟随做了平滑处理。平移不是直接赋值,而是通过一个带缓动的快速补间,所以镜头有轻微的跟拍延迟,比硬跟随自然得多。
展开是把同一条时间线推到底。点击按钮时,地图宽度动画到满屏,同时把整条滚动时间线的进度补间到 1,路线自动画完——不用为“展开态”另写一套动画。
三处值得单独说的实现
其一,跟随用的是预创建的补间而不是每帧新建。脚本一开始就为横纵两个方向各建了一个可复用的快速补间函数:
const xTo = gsap.quickTo(".pov g", "x", { duration: 1, ease: "expo" });之后每次更新只是调用它并传入新目标值。这类写法专门为“高频改同一个属性”设计,避免了在滚动回调里反复创建补间对象带来的开销与抖动。缓动选了指数型,特点是启动快、收尾极缓,用在跟拍上正好——快速滚动时镜头立刻跟上,停下时轻轻停稳。
其二,推近拉远是一段独立的小动画。它和路线绘制并列在同一条时间线的起点,但只占很短的时长,并设置了往返播放与一次重复。因为整条时间线绑定了滚动,这段缩放也就自然落在滚动行程的某个区间里,用户滚到那儿就会经历一次推近。想把“强调点”挪到别处,改它在时间线上的插入位置即可。
其三,展开与收起都锁了页面滚动。展开时把页面溢出设为隐藏,收起时恢复。这一步不能省:地图铺满屏幕后如果页面还能滚,被钉住的元素与滚动进度会打架,出现地图突然跳位的现象。窗口尺寸变化时脚本还会重置状态并刷新滚动触发器的测量值,这是所有钉住类动画都必须处理的一环。
拿到源码后能改什么
换地图就是换那张图片;换路线则是改 SVG 里那条路径的坐标串。实际操作中最省事的做法是:把地图图片放进任意矢量编辑工具,沿着实际路线画一条线,导出后把路径数据粘过来,起点的圆点坐标同步改成路径的第一个点即可。
视觉上可调的有:线的粗细与颜色(写在分组的描边属性上)、起点与动点的样式、地图的初始缩放与推近倍数(在那段缩放动画的两个数值上)。若路线很长,可以把初始缩放调大一些,让画面更贴近地面。
布局是左右各半的分屏,右侧内容区宽度与内边距都是百分比,改成左文右图只需交换定位。流程表那块深色卡片是独立样式,可以直接复用到别的段落。移动端建议改成上下堆叠,并把地图高度限制在半屏以内。
运行提示:动画依赖 GSAP 及其滚动触发、路径绘制、运动路径三个插件,页面从 CDN 加载,离线或内网环境需先下载到本地并改引用路径。地图为普通图片,可自行替换为任意底图。建议使用近两年版本的 Chrome、Edge、Firefox 或 Safari。详细运行方法请参见压缩包内的帮助文档。
关于滚动路线地图的常见问题
能不能在路线上加沿途站点标记?
可以。在 SVG 里按坐标加上圆点或图标,再给它们各自加一段在时间线特定位置淡入的动画即可,位置换算和路线用的是同一套坐标系。
可以接真实地图服务吗?
可以,但那样就要用对方的接口画线,样式与动画控制会受限。若只是展示一条固定路线,用静态底图加 SVG 路径通常更轻、更可控,也不用担心接口配额。
手机上体验如何?
左右分屏在窄屏上会显得局促,建议加媒体查询改成上下布局。展开全屏地图的交互在触摸设备上同样可用,收起按钮位置固定在右下角。
滚动到底部时地图有时会跳一下?
多为钉住区间与页面实际高度不匹配所致。确认外层区块的高度足够容纳整段动画行程,并在内容或窗口尺寸变化后刷新一次滚动触发器的测量——源码在窗口尺寸变化时已经这么做了。
它适合什么内容
凡是“要讲清一条路线”的页面都合适:城市马拉松与骑行活动、徒步与旅游线路、门店探访路线、物流与配送流程的可视化,甚至可以把地图换成流程图,用同样的方式逐段揭示一个业务流程。路径绘制、镜头跟随、推近强调与全屏展开的完整写法都在源码里,代码量很小,下载后可查看。