スクロールすると要素が固定され後続の要素が重なるアニメーション
おしゃれなサイトでよく見かける、スクロールに応じて要素が固定され後続の要素が重なるアニメーションの実装方法について解説しています。JavaScirptを使用した実装例とCSSで対応した実装例を紹介しています。
JavaScriptでの実装例
下記が実装例です。
※最後の要素が親要素を突き抜ける不具合がありましたので一部コードを修正しました(2026/01/02)。
スクロールに応じて数字を配置したボックスエリアが固定され、後続のボックスエリアが上に重なるようにしてアニメーションしています。
アニメーションを指定していない場合と比較して、より長くボックスエリアを見てもらうことができるので、重要なセクションなどに使用すると効果的かもれません。
解説
HTMLでは固定するセクションにdata-section属性を、その子要素にdata-section-inner属性を設定しています。最後のセクションは固定しないためdata属性は設定していません。
<section class="section" data-section> <div class="section__inner" data-section-inner>1</div></section><section class="section" data-section> <div class="section__inner" data-section-inner>2</div></section><section class="section" data-section> <div class="section__inner" data-section-inner>3</div></section><section class="section" data-section> <div class="section__inner" data-section-inner>4</div></section><section class="section"> <div class="section__inner">5</div></section>CSSでは、固定するセクションとその子要素の高さをビューポートの高さに設定しています。このようにすることで画面いっぱいで重なるアニメーションを実現することができます。
.section { height: 100svh; /* 以下省略 */}
.section__inner { height: inherit; /* 以下省略 */}JavaScriptの処理を言語化
JavaScriptではGSAPのScrollTriggerを使用しています。それぞれCDN等から読み込んでください。
const setFixed = () => { gsap.set(inner, { position: "fixed", bottom: 0, });};
const setAbsolute = () => { gsap.set(inner, { position: "absolute", bottom: "auto", });};
ScrollTrigger.create({ markers: true, trigger: section, start: "bottom bottom", onEnter: setFixed, onEnterBack: setFixed, onLeave: setAbsolute, onLeaveBack: setAbsolute,});section要素をトリガーにし、トリガーの底部がビューポートの底部に到達した時点でアニメーションが発動します。
onEnterとonEnterBackではsetFixed関数を実行し、セクションの子要素のpositionを固定し、bottomを0に設定しています(つまりセクションの子要素は画面いっぱいで固定されます)。
onLeaveとonLeaveBackではsetAbsolute関数を実行し、セクションの子要素のpositionの固定を解除し、bottomをautoに設定しています(つまりセクションの子要素は親要素の範囲に収まります)。
CSSでの実装例
CSSで実装した実装例は以下のとおりです。
解説
HTMLではセクションを囲う親要素(wrapper)を新たに追加しています。セクションの子要素は削除し、セクション要素の中にダイレクトにコンテンツを入れています。
<div class="wrapper"> <section class="section">1</section> <section class="section">2</section> <section class="section">3</section> <section class="section">4</section> <section class="section">5</section></div>CSSではセクションの高さを画面いっぱいに広げた上で、position: sticky;とtop: 0;を指定しています。これによりスクロールした際に画面上部に張り付いた状態を実現しています。
.section { height: 100svh; position: sticky; top: 0; display: grid; place-items: center; font-size: 10vw; color: green;}2026年現在、ほとんどの主要ブラウザでposition: sticky;は問題なく機能するので、コードをシンプルに保ちたい場合はCSSでの実装がおすすめです。
ただし、より複雑なタイミング制御やアニメーション効果が必要な場合は、JavaScriptでの実装を検討すると良いでしょう。
