[CSS] position: sticky;を使用して、スクロール時に画像をズームさせるページのレイアウトを実装する方法
Post on:2019年5月21日
CSSのposition: sticky;を使用して、スティッキーヒーローセクションを実装する方法について紹介します。
スティッキーヒーローセクションとは、画像などをスクロールした際に固定し、その固定された画像の上にスクロールさせるコンテンツ要素です。固定された画像はズームさせたり、オーバーレイにすることもできます。
How to create a Sticky Hero section
by CodyHouse
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
はじめに
わたし達は先日、スティッキーヒーローのコンポーネントを公開しました。このデモは、スクロールするとコンテンツを表示するスティッキーセクションです。
上記は、固定された画像をズームさせたデモで、オーバーレイにすることも簡単です。実際の動作は、デモページでご覧ください。
この記事では、このエフェクトを実装する方法を説明します。
※スクロールイベントは使用しません。
チュートリアルの動画
スティッキーヒーローを実装する方法を説明した動画を用意しました。記事を読みたい場合は、この動画はスキップしてください。
実装方法
このチュートリアルで構築するコンポーネントは、CodyHouseフレームワークに基づいています。
基本的な実装は、二つのセクションを用意することです。一つはスクロール時に固定したいメディア要素(例えば、画像)で、もう一つは固定されたメディア上をスクロールするコンテンツ要素です。
1 2 3 4 5 6 7 |
<section class="sticky-hero js-sticky-hero"> <div class="sticky-hero__media" aria-hidden="true"></div> <div class="sticky-hero__content"> <!-- content here --> </div> </section> |
メディア要素に「position: sticky;」を定義し、スティッキーさせます。
position: sticky;の解説記事: position: sticky;の仕組みや実際の使い方をやさしく解説
1 2 3 4 5 6 7 |
.sticky-hero__media { position: sticky; top: 0; height: 100vh; background: url(../img/bg-img.jpg) no-repeat center center; background-size: cover; } |
上記のコードでは、.sticky-hero__mediaとビューポートの間のオフセットがゼロ(top: 0;)になったらすぐに、要素を固定します。その位置は固定されているため(fixedではありません)、要素はコンテナ内でしか移動できず、スクロールを続けると移動します。
これで完了です! .sticky-hero__mediaがビューポートの一番上に到達するとすぐに固定され、.sticky-hero__contentがその上をスクロールし続けます。
このエフェクトはもう少し手を加えることができます。
.sticky-hero__mediaが固定された時に、それを検出してスタイルを変更してみましょう。例えば、メディア要素のサイズを変更するなど、視覚的に面白い効果を与えることができます。
1 2 3 |
.sticky-hero--media-is-fixed .sticky-hero__media { transform: scale(0.9); } |
エフェクトを加えるには、JavaScriptが少し必要です。
スクロールの正確な値を知る必要はなく、.sticky-hero__contentがビューポートといつ交差し始めたかを知る必要があります。そのため、スクロールイベントではなく、Intersection Observer APIを使用します。
Intersection Observerの解説記事: Intersection Observerが簡単で便利!要素がビューポートに表示されているかを判定できる
.sticky-hero__contentをJavaScriptでチェックし、ビューポートとの交差がゼロより大きい場合は、 .sticky-hero--media-is-fixedクラスを加えるようにします。
1 2 3 4 5 6 7 8 9 |
function initStickyHero(hero) { var observer = new IntersectionObserver(stickyCallback.bind(hero), {threshold: [0, 0.1, 1]}); observer.observe(hero.content); }; function stickyCallback(entries) { var bool = entries[0].intersectionRatio > 0; Util.toggleClass(this.element, 'sticky-hero--media-is-fixed', bool); }; |
これで完了です!
sponsors