前言
CSS
view ()
方法可能会标志着 JavaScript 在制作滚动动画方面的衰落。今日前端早读课文章由 @Digvijay Mahapatra 分享,@飘飘翻译。
译文从这开始~~
如何用 5 行 CSS 代码取代 50 多行繁琐的 JavaScript,彻底改变网页动画
每次和 UI/UX 设计师开完会,只要他们让我实现滚动动画,我内心都忍不住想大声尖叫。为什么?因为我真的讨厌写滚动动画!虽然这种效果看起来很棒,实现起来也 “相对简单”,但也有不少棘手的问题需要解决,尤其是当页面上有大量动画元素时。然而,当客户要求那些 “滚动时淡入” 的炫酷效果时,你又能怎么办呢?只能撸起袖子写些 JavaScript 代码,哪怕这会让你内心隐隐作痛。
JavaScript 时代(又名 “黑暗时代”)
过去,我经常写这样的代码(如果你现在还在这么做,我感同身受):
window.addEventListener(‘scroll’,()=>{
const elements = document.querySelectorAll(‘.fade-in’);
elements.forEach(element=>{
const elementTop = element.getBoundingClientRect().top;
const windowHeight = window.innerHeight;
if(elementTop < windowHeight *0.8){
element.style.opacity = ‘1’;
element.style.transform =‘translateY(0)’;
}
});
});
我当时的做法是修改 CSS 属性,或者给需要动画的元素添加类名,让其施展了些魔法。但更麻烦的是,我还得实现动画的反向效果,整个过程既繁琐又丑陋,而且我超级讨厌这样做。可怜的浏览器在每次滚动事件时都要处理这些计算,有时我都能听到它的哀鸣。在手机上,电池指示器会突然电量骤降。
随着对 JavaScript 了解得越来越深入,我开始使用防抖(debouncing)技术来减少计算次数。当然,这确实有所改进,但这难道就是最好的办法了吗?
发现 Intersection Observer(希望的曙光)
后来,我找到了 Intersection Observer API。终于,出现了更好的方法!相比不断监听滚动位置,我可以直接告诉浏览器:“嘿,当这个元素出现在视口时提醒我”—— 这样就省去了很多不必要的计算:
const observer =newIntersectionObserver((entries)=>{
entries.forEach(entry=>{
if(entry.isIntersecting){
entry.target.classList.add(‘visible’);
observer.unobserve(entry.target);// Fire and forget!
}
});
},{threshold:0.2});
document.querySelectorAll('.animate-on-scroll')
.forEach(el=> observer.observe(el));
结合一些 CSS:
.animate-on-scroll {
opacity: 0;
transform:translateY(20px);
transition: all 0.6s ease-out;
}
.animate-on-scroll.visible{
opacity: 1;
transform:translateY(0);
}
这确实比以前的做法好太多了!但还是有点不对劲 —— 动画要么开,要么关,缺少基于滚动位置的流畅控制。每当客户要求那种超级丝滑的视差(parallax)效果或渐进式展示(progressive reveal),我又得回去写复杂的
JavaScript
代码,或者使用在网上找到的 CSS 技巧。
一切改变了:CSS
view()
函数
然后,CSS 之神赐予了我
view()
。我的天,简直神迹!来看这段代码:
@keyframes fadeIn {
from{
opacity: 0;
transform:translateY(20px);
}
to{
opacity: 1;
transform:translateY(0);
}
}
.fade-in{
animation: fadeIn linear;
animation-timeline:view();/* 关键点 */
animation-range: entry 10% cover 30%;/* 精彩之处 */
}
就是这样!无需
JavaScript
。无需事件监听器。没有性能噩梦。只有顺滑流畅的动画,响应滚动操作。
想玩点更花哨的?如果你想让元素在滚动进入时淡入,在滚动离开时淡出?完全没问题!
@keyframes fadeInOut {
0%{
opacity