GODRICH

スクロール アニメーション CSSで作る9種 — コピペでApple風

スクロール アニメーション CSSは、指でページを下へスクロールする動きに画面が応える仕組みで、Appleの製品ページがその基準です。スクロール用ライブラリ一切なしのCSSだけで、横流しパネル・固定画面の切替・単語の着色・背景色の入れ替えまで9種を、実際にレンダリングして確かめたコードでまとめました。

自動再生 · タイルを押すとその項目へ · すべて1つのzip

9種は画面に現れる順番です。ページを開いた瞬間に見えるもの(01)から始まり、本文が終わって出会うもの(02)、本文の流れの中でカードが積まれ文が満ちていくもの(03〜07)、そして一覧が速度に応じたり一枚の画像が公開されたりする締め(08〜09)の順です。Apple風ページを上から下へひと息になぞる道と同じです。

01横へ流れるストーリーパネル

縦にスクロールすると、固定された画面の中でパネルが横へ流れていく、Apple製品ページの定番構成です。scroll-timelineがスクロール箱の位置をそのまま読んでトラックを押し、position: stickyが画面を固定します。製品の特徴紹介やポートフォリオのストーリーに使います。

animation-timeline: scroll()scroll-timeline: --hp-scrollposition: sticky
.hp__scroller {
  overflow-y: auto;
  scroll-timeline: --hp-scroll block;
}
.hp__inner { height: 300%; }          // スティキ領域が画面3枚分
.hp__pin {
  position: sticky;
  top: 0;
  height: calc(100% / 3);
  overflow: hidden;
}
.hp__track {
  display: flex;
  width: 300%;                        // パネル3枚 = 画面の300%
  animation: hp-slide linear both;
  animation-timeline: --hp-scroll;
}
@keyframes hp-slide {
  from { transform: translateX(0); }
  to   { transform: translateX(-66.6667%); } // 2枚分 ÷ トラック幅
}

02終わりで現れるカーテンフッター

本文パネルがフッターの上を進み、スクロールの終わりで脇に退いてフッターをカーテンのように現します。フッターは文書の一番最後に置きつつ、position: sticky; bottom: 0で最初からビューポートの底に貼り付けておきます。連絡先・著作権のフッターや締めの挨拶に合います。

z-indexposition: stickySafari에서도 그대로
.fc__main {
  position: relative;
  z-index: 1;                    // 本文がフッターの上を進む
  min-height: calc(100% + 64px); // 最初からフッターを完全に覆う
  margin-bottom: 64px;           // 終わりでフッターの枠が開く
  background: #fff;
}
.fc__foot {
  position: sticky;
  bottom: 0;
  z-index: 0;
  height: 64px;
  background: linear-gradient(120deg, #b9f0d8, #ffd6e8);
}

03重ねて積まれるカード

カードごとにposition: stickyが効いていて、次のカードが覆いかぶさり、過ぎたカードは積まれたまま残ります。topの値を1枚ずつ深くすると、重なる間隔が生まれます。サービス紹介のステップや料金プランの比較カードに使います。

position: stickytop 간격JS 0줄
.sk__card {
  position: sticky;
  min-height: 40px;
  margin-bottom: 8px;
  border-radius: 16px;
  box-shadow: 0 6px 12px rgba(23, 20, 26, .32);
}
.sk__card--1 { top: 8px;  background: #ffd6e8; }
.sk__card--2 { top: 16px; background: #d3ecff; }
.sk__card--3 { top: 24px; background: #e4f7d9; }
.sk__card--4 { top: 32px; background: #fff3c9; }

04固定画面のシーン切替

画面は固定したまま、スクロール量に応じてシーンが交互にゆっくり切り替わる、スクロールテリングの核心動作です。シーン3枚がスクロールタイムライン1本を共有し、キーフレームの区間で分け合います。3ステップの使い方案内や製品ストーリーに使います。

animation-timeline: scroll()키프레임 구간opacity
.ps__scroll {
  overflow-y: auto;
  scroll-timeline: --ps-scroll block;
}
.ps__pin {
  position: sticky;
  top: 0;
  height: calc(100% / 3);
  display: grid;
}
.ps__scene--1 { animation: ps-1 linear both; animation-timeline: --ps-scroll; }
.ps__scene--2 { animation: ps-2 linear both; animation-timeline: --ps-scroll; }
.ps__scene--3 { animation: ps-3 linear both; animation-timeline: --ps-scroll; }
@keyframes ps-1 { 0% { opacity: 1; } 33%, 100% { opacity: 0; } }
@keyframes ps-2 { 0%, 30% { opacity: 0; } 38%, 62% { opacity: 1; } 70%, 100% { opacity: 0; } }
@keyframes ps-3 { 0%, 64% { opacity: 0; } 74%, 100% { opacity: 1; } }

05単語ごとに満ちる文章

文中の単語がスクロール位置に合わせてひとつずつはっきり浮かび上がる、Appleの紹介文で見かける演出です。単語ごとに自分のview()タイムラインが付くので、遅延を別に与えなくても位置の関係が自然に順番を作ります。ランディングの最初の一文やブランドの宣言コピーに使います。

animation-range 겹침view()글자색만
.wf__w {
  color: rgba(23, 20, 26, .16);   // 薄い状態が基本
  animation: wf-in linear both;
  animation-timeline: view();     // 単語それぞれのタイムライン
  animation-range: entry 0% cover 42%;
}
@keyframes wf-in {
  from { color: rgba(23, 20, 26, .16); }
  to   { color: #17141a; }
}

06蛍光ペンが引かれる強調

スクロールが届くと、強調したい言葉の後ろに蛍光ペンの色が左から右へと塗られていきます。文字はそのままに、背景グラデーションの幅(background-size)だけを伸ばすのが要点です。セクション見出しの強調やセールのコピーに使います。

background-sizeview()글자 안 건드림
.mk__hl {
  background: linear-gradient(#2f6df6, #2f6df6) no-repeat 0 62%;
  background-size: 0% 58%;
  padding: 0 4px;
  animation: mk-sw linear both;
  animation-timeline: view();
  animation-range: entry 30% cover 60%;
}
@keyframes mk-sw {
  from { background-size: 0% 58%; }
  to   { background-size: 100% 58%; }
}

07区間ごとに変わる背景色

ページを下へスクロールする間、背景色がセクションごとに滑らかに入れ替わり、場面が変わるような感覚を与えます。背景レイヤーをposition: stickyで後ろに貼り、スクロールタイムラインが色のキーフレームを回します。ストーリー型ランディングやルーティン・料金案内に使います。

animation-timeline: scroll()background-colorroot 타임라인
.ts__scroll {
  overflow-y: auto;
  scroll-timeline: --ts-scroll block;
}
.ts__bg {
  position: sticky;
  top: 0;
  height: 100%;
  margin-bottom: -100%;  // セクションを背景の上へ引き上げる
  animation: ts-bg linear both;
  animation-timeline: --ts-scroll;
}
@keyframes ts-bg {
  0%   { background-color: #fff7e6; }
  50%  { background-color: #b8f0d0; }
  100% { background-color: #ff9db8; }
}

08スクロール速度で傾く一覧

スクロールを速くすると一覧カードがその速度ぶん傾き、止まると元の姿に戻ります。速度を測る短いスクリプトが--vel変数に値を入れ、傾きの計算はCSSのcalcが担います。ギャラリーフィードやニュース・マガジン一覧に使います。

JS 10줄--vel 변수skewY
var box = document.querySelector('.feed');
var last = box.scrollTop, vel = 0;
box.addEventListener('scroll', function () {
  vel = Math.max(-24, Math.min(24, box.scrollTop - last));
  last = box.scrollTop;
});
(function decay() {
  vel *= 0.86;
  box.style.setProperty('--vel', vel.toFixed(2));
  requestAnimationFrame(decay);
})();
.feed__row {
  transform: skewY(calc(var(--vel, 0) * -0.18deg));
}

09スポットライトサークル

固定画面で丸い窓がスクロールに合わせて大きくなり、隠していた画像を現します。明るい画面を上に重ね、clip-path: circle()の半径をスクロールタイムラインで広げます。製品のお披露目シーンやアーティスト紹介に使います。

clip-path: circle()scroll-timeline: --sl-scroll이미지 공개
.sl__spot {
  grid-area: 1 / 1;
  background: linear-gradient(135deg, #2f6df6, #8fb4ff);
  clip-path: circle(14% at 50% 50%);
  animation: sl-open linear both;
  animation-timeline: --sl-scroll;
}
@keyframes sl-open {
  from { clip-path: circle(14% at 50% 50%); }
  to   { clip-path: circle(75% at 50% 50%); }
}

どこで壊れるか — 落とし穴ひとつ

いちばん刺さった落とし穴は、position: stickyが流れの中で自分の枠を取り続けるという点でした。02を最初に作ったときフッターを本文の前に置いたところ、最後までスクロールしてもフッターが一度も現れませんでした。フッターを文書の一番最後に移し、本文にmargin-bottomを与えて初めて、本文がフッターの上を進み終わりで脇に退く絵ができました。07も同じ病にかかりました。背景レイヤーをstickyにしただけで流れの中で画面1枚分を占領し、セクションのチップが画面の下に押しやられて1枚もキャプチャに映らず、margin-bottom: -100%で引き上げて初めて背景の上に乗りました。もうひとつ、この記事のスクロールタイムライン(scroll()view())はインストールされたChromeで直接レンダリングして確かめましたが、FirefoxとSafariはまだ対応していません。対応していないブラウザでは、05の文章は最初からはっきりし、09の丸い窓は最初から開いた状態で固定されます。だからスクロールタイムラインを使う6種(01・04・05・06・07・09)には@supports notなどのフォールバックを用意し、9種すべてでスクロール自体はどのブラウザでも止まらないようにしました。9つのフォルダをこうして確かめ直してから圧縮し、案内どおりにry7akxw2を入力すると成果物がそのまま開きます。

アクセシビリティ

9種ともprefers-reduced-motion: reduceで自動的に動く部分が止まります。05の単語は最初から濃い色に、06の蛍光ペンは最初から引き終わった状態に、09の円は大きく開いた状態に固定され、08は速度反応そのものを鍵にかけてカードが傾かないようにしました。スクロール箱の中はTabキーで要素を順に訪れられ、04のように画面が固定される構成でも、次のセクションがすぐ下に続くのでキーボードで最後まで読めます。

FAQ

スクロールアニメーションを入れるとサイトは重くなりますか?

01・04・05・06・07・09のスクロールタイムラインと02・03のスティキは、ブラウザがレンダリング段階で直接処理するので、毎フレームJavaScriptが計算する方式よりむしろ軽いです。08だけはスクリプトが毎フレーム値を更新しますが、していることは変数に数字を1つ入れるだけなので負担は小さいです。

FirefoxやSafariではどう見えますか?

スクロールタイムラインを使う01・04・05・06・07・09は、対応できないブラウザではそれぞれ最終形で固定されます。パネル1が見え、文章ははっきりし、蛍光ペンは引かれ、円は開いています。02・03・08はこの機能と無関係なので、どのブラウザでも同じように動きます。

iPhoneでも動きますか?

02・03のスティキと06の背景の伸長は、iPhoneのSafariでもそのまま動きます。残りはiPhoneのSafariがまだ対応していないスクロールタイムラインを使うため、最終形で見えます。ただし画面の構造自体は崩れないので、内容を読む支障はありません。

スクロール系の演出はCSSアニメーションカテゴリにさらにあり、この記事はパララックス集スティキヘッダー集へ続きます。animation-timelineの正式な仕様はMDNのanimation-timelineで、position: stickyの動作はMDNのpositionで確認できます。

解凍パスワードを入力してください

パスワードはこの記事の本文の中にあります。読み進めると出てきます。