LoginSignup
12
2

More than 1 year has passed since last update.

パララックスならscrollイベントを間引かずとも@scroll-timelineで良いじゃない

Last updated at Posted at 2022-06-30

この記事の概要

パララックスを実装する際、setTimeoutthrottleで間引くケースがあると思います。

しかし、単にスクロール量にあわせてアニメーションがしたいだけならCSSの@scroll-timelineを使った方が簡単ですよ、と紹介する記事です。

@scroll-timelineを使えば、例えば以下のようなアニメーションがCSSだけでできるようになります。(楽しくなってパララックス以外の挙動も入れて作っちゃいましたが、ご容赦ください笑)

movie.gif

この記事を投稿している2022年6月30日現在、すべてのブラウザで利用不可です。
そのため、これは未来に向けた記事投稿です。
なお、Chromeの場合はchrome://flagsから#enable-experimental-web-platform-featuresのフラグを有効にしていれば一応見れます。

Data on support for the css-scroll-timeline feature across the major browsers from caniuse.com

使い方

@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はスクロールの向きを指定します。
horizontalverticalは、昔ながらの指定というか、書字方向関係無く水平か垂直かを指定します。
blockinlineは論理的プロパティにあわせての指定です。

scroll-offsetsは、スクロールの中でアニメーションが発生する場所を決められます。
そのため、指定したアニメーションのうち半分までを再生する、といった使い方もできます。

@keyframesを定義する

@scroll-timelineはあくまでスクロールの仕方なので、アニメーションそのものは別途定義せねばなりません。
CSSアニメーションについて書かれた記事は他にもあるので、説明はそちらに譲ります。

アニメーションさせたい要素にanimation-nameanimation-timelineを指定する

アニメーションさせたい要素に、これまで指定した中身を適用させます。

.element {
  animation-duration: 1000ms;
  animation-name: awesomeAnimation; /* @keyframesで定義した名前を指定する */
  animation-timeline: superTimeline; /* @scroll-timelineで定義した名前を指定する */
  background-color: #55c500;
  height: 100px;
  width: 100px;
}

完成

あとは具体的なスタイルを書けばOKです。

一応、今回書いたコードの全体像を載せておきます

index.html
  <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>
style.css
* {
  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でも情報を発信しているので、良かったらフォローお願いします!

12
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
2