この記事の概要
パララックスを実装する際、setTimeout
やthrottle
で間引くケースがあると思います。
しかし、単にスクロール量にあわせてアニメーションがしたいだけならCSSの@scroll-timeline
を使った方が簡単ですよ、と紹介する記事です。
@scroll-timeline
を使えば、例えば以下のようなアニメーションがCSSだけでできるようになります。(楽しくなってパララックス以外の挙動も入れて作っちゃいましたが、ご容赦ください笑)
使い方
@scroll-timeline
を定義する
@scroll-timeline custom-ident-name {
source: auto; /* auto | selector("id-selector") | none */
orientation: auto; /* auto | block | inline | horizontal | vertical */
scroll-offsets: none; /* none | <length-percentage> | <element-offset> */
}
custom-ident-name
は@keyframes
で名前をつけるのと同じ感覚です。
source
は、スクロールする要素を指定します。
何も指定しなければhtml全体を対象とします。
特定の要素を指定したい場合、class
ではなくid
を指定してください。
orientation
はスクロールの向きを指定します。
horizontal
とvertical
は、昔ながらの指定というか、書字方向関係無く水平か垂直かを指定します。
block
とinline
は論理的プロパティにあわせての指定です。
scroll-offsets
は、スクロールの中でアニメーションが発生する場所を決められます。
そのため、指定したアニメーションのうち半分までを再生する、といった使い方もできます。
@keyframes
を定義する
@scroll-timeline
はあくまでスクロールの仕方なので、アニメーションそのものは別途定義せねばなりません。
CSSアニメーションについて書かれた記事は他にもあるので、説明はそちらに譲ります。
アニメーションさせたい要素にanimation-name
とanimation-timeline
を指定する
アニメーションさせたい要素に、これまで指定した中身を適用させます。
.element {
animation-duration: 1000ms;
animation-name: awesomeAnimation; /* @keyframesで定義した名前を指定する */
animation-timeline: superTimeline; /* @scroll-timelineで定義した名前を指定する */
background-color: #55c500;
height: 100px;
width: 100px;
}
完成
あとは具体的なスタイルを書けばOKです。
一応、今回書いたコードの全体像を載せておきます
<body>
<div id="container">
<h1 class="heading">Scroll down<br />↓</h1>
<div class="column1 near green"></div>
<div class="column2 far blue"></div>
<div class="column3 middle black"></div>
<div class="column1 far black"></div>
<div class="column2 middle green"></div>
<div class="column3 near blue"></div>
<div class="column1 middle blue"></div>
<div class="column2 near black"></div>
<div class="column3 far green"></div>
<div class="column1 near green"></div>
<div class="column2 far blue"></div>
<div class="column3 middle black"></div>
<div class="column1 far black"></div>
<div class="column2 middle green"></div>
<div class="column3 near blue"></div>
<div class="column1 middle blue"></div>
<div class="column2 near black"></div>
<div class="column3 far green"></div>
<div class="column1 near green"></div>
<div class="column2 far blue"></div>
<div class="column3 middle black"></div>
<div class="column1 far black"></div>
<div class="column2 middle green"></div>
<div class="column3 near blue"></div>
<div class="column1 middle blue"></div>
<div class="column2 near black"></div>
<div class="column3 far green"></div>
<h1 class="heading">↑<br />Scroll up</h1>
</div>
</body>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
#container {
display: grid;
gap: 1rem;
grid-template-columns: 1fr repeat(3, 300px) 1fr;
padding-block: 20vh;
place-items: center;
width: 100%;
}
.heading {
font-family: "SF Pro", sans-serif;
font-size: 96px;
font-weight: bold;
grid-column: 2 / 5;
padding-block: 5vh;
text-align: center;
}
.column1 {
transform-origin: center right;
grid-column: 2 / 3;
}
.column2 {
grid-column: 3 / 4;
}
.column3 {
transform-origin: center left;
grid-column: 4 / 5;
}
.near {
animation-direction: alternate;
animation-duration: 1000ms;
animation-name: nearAnimation;
animation-timeline: moveTimeline;
border-radius: 48px;
height: 240px;
width: 240px;
z-index: 1;
}
.middle {
animation-direction: alternate;
animation-duration: 1000ms;
animation-name: middleAnimation;
animation-timeline: moveTimeline;
border-radius: 32px;
height: 160px;
width: 160px;
z-index: 0;
}
.far {
animation-direction: alternate;
animation-duration: 1000ms;
animation-name: farAnimation;
animation-timeline: moveTimeline;
border-radius: 16px;
height: 80px;
width: 80px;
z-index: -1;
}
.green {
background-color: #55c500;
}
.blue {
background-color: #4097db;
}
.black {
background-color: #1e2121;
}
@scroll-timeline moveTimeline {
orientation: vertical;
scroll-offsets: selector(#container) start 0, selector(#container) end 0;
source: selector("#container");
}
@keyframes nearAnimation {
0% {
transform: translateY(100%);
}
100% {
transform: translateY(-100%) rotate(360deg);
}
}
@keyframes middleAnimation {
0% {
transform: translateY(60%);
}
100% {
transform: translateY(-60%) rotate(360deg);
}
}
@keyframes farAnimation {
0% {
transform: translateY(10%);
}
100% {
transform: translateY(-2%) rotate(360deg);
}
}
最後まで読んでくださってありがとうございます!
Twitterでも情報を発信しているので、良かったらフォローお願いします!