文章在个人网站中发布,原文链接:记录一个纯CSS实现滚动驱动动画的效果
先看一下这个简单的案例
代码:
你也可以直接划到下边看效果。
<div class="out-cont"><!-- 最外层元素,用于框定元素需要固定的距离 --><div class="inner-cont"><!-- 内层元素,用于固定元素的位置 --><div class="animation-item"><!-- 播放动画的元素内容 --></div></div>
</div>
<style>
.out-cont {
/* 最外层元素,用于框定元素需要固定的距离,这里表示元素将被固定两个屏幕的高度 */width: 100%;height: 200vh;position: relative;
}
.inner-cont {
/* 内层元素,用于固定元素的位置,使用sticky使元素在范围内固定 */width: 100%;height: 50vh;position: sticky;top: 25vh;display: flex;align-items: center;justify-content: center;
}
.animation-item{
/* 播放动画的元素内容,使用animation-timeline实现滚动驱动动画 */width: 20%;aspect-ratio: 1;background-color: #2E74B5;animation: move 1s linear forwards;animation-timeline: view();animation-range: contain;
}
@keyframes move {0% {transform: rotate(0deg);border-radius: 8%;}50% {transform: rotate(360deg);border-radius: 50%;}100% {border-radius: 8%;transform: rotate(720deg);}
}
</style>
效果:
sticky:粘性布局
对于前端码农来说这个玩意并不陌生,所以就只简单介绍一下:
position:sticky是介于position:relative与position:fixed之间的一种布局方式。当父元素出现在屏幕中时它表现得像fixed,会把自己固定在屏幕上。当父元素出现在屏幕外时它表现得像relative,会按照正常的文档流进行布局,被父容器带走。
关于这个案例是如何使用sticky实现类似元素固定的效果的,上面效果示例右边有一个简单的展示,可以帮助理解。而且这个展示也是纯css的哦。
sticky元素的所有父级都不能设置overflow:hidden,这样会使sicky无效,实在需要可以使用overflow:clip代替。
animation-timeline:滚动驱动动画
这是本案例的核心,元素上使用了这个属性,@keyframes
定义的css动画将不会自动播放,而是根据滚动条的进度进行滚动。
这个属性有两个主要属性值:
- animation-timeline: view()
元素进入视口时开始播放动画,离开视口时结束。 - animation-timeline: scroll()
元素将在整个滚动容器中滚动时播放动画。 - animation-timeline:cont-name
命名容器,这个待会展开讲。
animation-timeline: scroll()
scroll()是对于整个页面的,相对而言比较简单,用于做一些与全局滚动相关的效果,例如文章阅读进度,这里引用前端侦探的一张图。
scroll()中可以填入两个参数:scroller和axis
-
scroller
scroller参数用于指定滚动容器,默认值为nearest
。
如果设置为nearest
,将会使用最近的祖先滚动容器。
如果设置为root
,将会使用文档视口作为滚动容器。
如果设置为self
,将会使用元素本身作为滚动容器。 -
axis
axis参数用于指定滚动轴,默认值为block
。
如果设置为block
,滚动容器的块级轴方向。
如果设置为inline
,滚动容器内联轴方向。
如果设置为x
,则元素将在水平方向上滚动。
如果设置为y
,则元素将在垂直方向上滚动。
animation-range
如果我不想让动画整个滚动期间都播放呢,可以使用animation-range
属性设置动画的起止位置,px
,%
单位均可。
例如:
.animation{animation-range: 0 100px;
}
这样动画就只会在滚动容器滚动到0到100px的位置时播放,在100px之后就不会再播放了。
animation-timeline:view()
view()是相对于元素与视口的位置的,这个案例就是基于view()的。
view()中也可以填入两个参数:axios和inset
-
axis
axis参数用于指定滚动轴,默认值为block
。
如果设置为block
,滚动容器的块级轴方向。
如果设置为inline
,滚动容器内联轴方向。
如果设置为x
,则元素将在水平方向上滚动。
如果设置为y
,则元素将在垂直方向上滚动。 -
inset
inset参数用于规定动画从何时开始何时结束,是元素刚冒尖尖就开始还是元素完全进入视口呢,就靠这个属性控制,有点类似于上面animation-range
的作用。
inset接受一个或两个值,两个值时代表开始位置和结束位置,px
,%
单位均可
animation-timeline:cont-name
你可能发现了,仅靠上面那些属性,只能实现父元素滚动驱动子元素的动画,要是我需要滚动一个容器去驱动另一个兄弟元素的动画呢?就需要靠命名的容器实现了。
使用很简单,就是在滚动容器上使用一个属性scroll-timeline-name
。
.scroll{/* 命名滚动容器 */scroll-timeline-name: --my-scroller;
}
.animation{/* 需要被驱动动画的元素 */animation-timeline: --my-scroller;
}
这样.scroll
容器被滚动时,.animation
元素就会根据滚动容器的滚动进度进行动画播放。
相关知识
position:fixed
animation-timeline
animation-range
前端侦探