引言

前几天偶然点开了 GTA 6 的官方网站,瞬间就被那个效果震撼到了——随着鼠标滚动,背景视频居然在同步播放!整个页面的排版精致流畅,每一帧都像是精心编排的电影镜头。

作为一个对前端技术充满好奇的人,我的第一反应是:”这到底是怎么实现的?”

看了源代码之后,我发现了一个有趣的真相:这个看似复杂的效果,原理其实非常简单

核心发现:视频 + 滚动控制

GTA 6 官网的核心实现思路是:

  1. 提前准备一个视频:整个”动画”实际上是一个预渲染的视频文件
  2. 监听滚动事件:通过 JavaScript 监听用户的滚动行为
  3. 同步播放进度:根据滚动位置控制视频的播放时间
  4. 优雅降级:有网络时播放视频,无网络时显示静态图片

这就好比你在用进度条拖动视频,只不过这个”进度条”是页面的滚动条。

我的实验项目

按照这个思路,我快速搭建了一个实验性网站:

📁 项目地址: Story-Telling-Example4-UE5

这个项目本身没有任何实际内容,纯粹是一次技术探索。我使用了一段虚幻引擎 5 渲染的视频作为演示素材。

实现方法

HTML 结构

1
2
3
4
5
6
7
8
<div class="video-container">
<video id="scrollVideo" preload="auto">
<source src="your-video.mp4" type="video/mp4">
</video>
<div class="content">
<!-- 你的滚动内容 -->
</div>
</div>

CSS 基础样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.video-container {
position: relative;
height: 400vh; /* 创造滚动空间 */
}

#scrollVideo {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
object-fit: cover;
}

.content {
position: relative;
z-index: 10;
}

JavaScript 核心逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
const video = document.getElementById('scrollVideo');
const container = document.querySelector('.video-container');

// 监听滚动事件
window.addEventListener('scroll', () => {
const scrollTop = window.scrollY;
const containerHeight = container.offsetHeight - window.innerHeight;

// 计算滚动进度 (0 到 1)
const scrollProgress = Math.min(scrollTop / containerHeight, 1);

// 同步视频时间
const videoDuration = video.duration;
video.currentTime = scrollProgress * videoDuration;
});

// 防止视频自动播放
video.pause();

// 可选:优化性能,使用 requestAnimationFrame
let ticking = false;
window.addEventListener('scroll', () => {
if (!ticking) {
window.requestAnimationFrame(() => {
const scrollTop = window.scrollY;
const containerHeight = container.offsetHeight - window.innerHeight;
const scrollProgress = Math.min(scrollTop / containerHeight, 1);
video.currentTime = scrollProgress * video.duration;
ticking = false;
});
ticking = true;
}
});

关键技巧总结

技巧 说明
视频预加载 使用 preload="auto" 确保视频在滚动前已加载
固定定位 视频使用 position: fixed 保持全屏背景
滚动空间 容器高度设为 400vh 创造足够的滚动距离
进度映射 将滚动位置映射到视频时间戳
性能优化 使用 requestAnimationFrame 限制更新频率
优雅降级 为无网络场景准备静态备用图

效果对比

GTA 6 官网效果演示

GTA 6 官网的滚动视频效果

我的实现效果

我的实验项目效果

常见问题

问题 现象 根因 解决步骤
视频卡顿 滚动时视频不流畅 视频文件过大或未预加载 压缩视频、使用 preload=”auto”
同步不准确 视频进度与滚动不匹配 容器高度计算错误 确保 containerHeight = 容器offsetHeight - 窗口innerHeight
移动端失效 手机上滚动无反应 移动端滚动事件机制不同 添加 touch 事件监听或使用 Intersection Observer
视频不显示 只能看到黑屏 视频路径错误或格式不支持 检查视频路径、确保使用 H.264 编码的 MP4

实用技巧

🎬 视频准备建议

  1. 时长控制:建议视频时长 5-15 秒,太长会影响体验
  2. 编码格式:使用 H.264 编码的 MP4 格式,兼容性最好
  3. 分辨率:1080p 足够,4K 会导致加载过慢
  4. 压缩优化:使用 Handbrake 或 FFmpeg 进行压缩

📊 性能优化要点

1
2
# 使用 FFmpeg 压缩视频的示例命令
ffmpeg -i input.mp4 -c:v libx264 -crf 28 -preset slow output.mp4

🔧 进阶扩展

  • 双向滚动:支持向上滚动时视频倒退
  • 速度控制:根据滚动速度调整视频播放速率
  • 分段加载:长视频分段加载,减少初始加载时间
  • 检测支持:判断浏览器是否支持视频播放

相关资源

结语

这次探索让我意识到,很多看似复杂炫酷的效果,背后的原理往往出奇简单。关键是要有好奇心去拆解、去尝试。

如果你也对这种效果感兴趣,欢迎参考我的 GitHub 项目,或者直接 fork 下来玩耍。代码很简单,但创意无限~