模仿钉钉官网动画
钉钉官网有个与滚动条绑定的页面动画,还是非常有创意的,但是我最早遇到类似动画效果的是苹果官网。
让我们动手来实践一下类似的效果,做完后将会得到一个类似的效果。
不随滚动条移动的布局就是固定布局。但是 sticky
的布局方式,会使得我们实现这个效果更加容易。
我们将外层定一个比较高的高度,使得滚动条可以滚动,内层使用 sticky
布局,使得视口内,我们一直看到的是这一屏,这样我们才能在后续在这一屏上做动画。
sticky
的好处就是,在进入视口后,它会自动有一个固定布局的效果,父容器离开视口后,会自动实效,无需 JS 的参与,所以非常方便。
剩下的就是如何执行动画了,这一步就非常自由了,比如钉钉是在 DOM 元素上应用动画,我的例子使用了 Lottie 来播放动画。
我的需求时,在第二屏完全进入视口后,开始播放动画第一帧,在第三屏进入视口前,就是动画的最后一帧。
这样我们就可以得到一个滚动位置的开始位置和结束位置。
开始位置是第二屏的整体元素的 offsetTop
。
结束位置是在开始位置的基础上加上第二屏的整体高度,再减去一个屏幕的大小,即 scroller.offsetTop + scroller.clientHeight - document.documentElement.clientHeight
。
由于我用的 Lottie 动画是 121 帧的,所以我需要计算一下滚动多少距离后播放一帧 (121 / (end - start) * (curr - start)) >> 0
,我使用了位运算来取整。
这样,就能实现我截图中的动画效果了,整体来说并不难,但是却可以得到一个不错的效果,感觉更考验设计师吧。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + TS</title>
</head>
<body>
<div class="screen">Screen 1</div>
<div class="ani-screen">
<div class="screen">
<lottie-player
mode="normal"
src="https://assets2.lottiefiles.com/packages/lf20_riAqnQrYxZ.json"
style="width: 320px"
>
</lottie-player>
</div>
</div>
<div class="screen">Screen 3</div>
<script src="https://unpkg.com/@lottiefiles/lottie-player@1.5.7/dist/lottie-player.js"></script>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
body {
margin: 0;
}
.screen {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
font-size: 60px;
}
.ani-screen {
height: 3000px;
}
.ani-screen > .screen {
position: sticky;
top: 0;
}
import './style.css'
const scroller = document.querySelector('.ani-screen')!
const player = document.querySelector("lottie-player") as any;
document.addEventListener('scroll', function () {
let curr = window.scrollY
let start = scroller.offsetTop
let end = scroller.offsetTop + scroller.clientHeight - document.documentElement.clientHeight
if (curr >= start && curr <= end) {
player.seek(
(121 / (end - start) * (curr - start)) >> 0
);
}
});
如果不想手写这个效果的逻辑,我看到了有现成的三方库可以选用:lax.js