これでCSSのみで実装できる! スクロール方向に合わせてヘッダを非表示・表示する方法を解説
Post on:2024年10月10日
Webページを表示し、スクロールダウンするとヘッダが非表示になり、ページのどこからでもスクロールアップするとヘッダが再び表示される、というのを見たことがあると思います。
これまでは実装するにはJavaScriptが必要でしたが、CSSのみで実装できる方法を紹介します。
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
- はじめに
- CSS Scroll-Driven Animationsでスクロール方向を検出する
- transition-delayプロパティを使ったテクニック
- ヘッダをスクロール時に表示・非表示されるデモ
はじめに
CSSでヘッダをスクロールダウンで非表示に、スクロールアップで表示するときにこのテクニックを知っておくと便利です。
特定の条件下でCSSプロパティにtransition-delay
を追加すると(スタイルクエリを使用して実行)、条件が適用されなくなった後でもその値を持続させることができます。
See the Pen
Hide on Scroll Down, Show on Scroll Up Header by coliss (@coliss)
on CodePen.
CSS Scroll-Driven Animationsでスクロール方向を検出する
Solved by CSS Scroll-Driven Animationsの記事にアクティブなスクロール方向とスクロール速度に基づいた要素をスタイルするデモがあります。その中の一つに、スクロールダウンした時に非表示になるヘッダ要素があります。
下記はそのデモで、上下にスクロールするとヘッダが非表示になり、アイドル状態の時は再び表示されます。デモはChrome 115+でご覧ください。
See the Pen
CSS scroll-direction detection with Scroll-Driven Animations with moving header by coliss (@coliss)
on CodePen.
CSS Scroll-Driven Animationsについて詳しくは、下記をご覧ください。
Scroll-driven AnimationsでCSSでの実装が大きく変わる! スクロールをトリガーにしたアニメーションを実装する方法
このデモのCSSには、特定の方向にスクロールしているときに0
か1
になるCSSの変数があります。CSSは下記の通りです。
1 2 3 4 5 6 7 8 |
--when-scrolling: abs(var(--scroll-direction)); --when-not-scrolling: abs(var(--when-scrolling) - 1); --when-scrolling-up: min(abs(var(--scroll-direction) - abs(var(--scroll-direction))), 1); --when-scrolling-down: min(var(--scroll-direction) + abs(var(--scroll-direction)), 1); --when-scrolling-down-or-when-not-scrolling: clamp(0, var(--scroll-direction) + 1, 1); --when-scrolling-up-or-when-not-scrolling: clamp(0, abs(var(--scroll-direction) - 1), 1); |
transition-delayプロパティを使ったテクニック
記事で解説したように、これらの変数は一時的なものです。スクロールを止めた瞬間に--when-not-scrolling
を除くすべての変数は再び0
に戻ります。したがって、ヘッダはスクロールを止めると再び表示されます。
よりよいエクスペリエンスとしては、下にスクロールするときにヘッダを非表示にし、再び上にスクロールする瞬間までその状態を維持させることです。しかし、当時はそれを実現する解決策は見つかりませんでした。
CSS Day 2024でScheppはこれらのカスタムプロパティを「固定」する方法を見つけたことを共有しました。そのテクニックは、特定の方向にスクロールするときにプロパティのtransition-duration
を長く設定することです。
下記のCSSがそれです。アイドル状態のときにトランジションが無期限に停止します。こうすることで--scroll-*
カスタムプロパティは再びスクロールを開始するまでその値を保持します。
1 2 3 4 5 |
@container style(--scroll-direction: 0) { header { transition-delay: calc(infinity * 1s); } } |
ヘッダをスクロール時に表示・非表示されるデモ
このテクニックをすぐに使用する時間がなかったのですが、Fabrizio CalderanからXのポストで連絡がありました。それが下記のデモです。
ヘッダは最初は表示されていて、スクロールダウン時に非表示に、そしてどの場所でもスクロールアップ時に表示されます。
See the Pen
Hide on Scroll Down, Show on Scroll Up Header by coliss (@coliss)
on CodePen.
Fabrizioはスタイルクエリで設定するトランジションビヘイビアを利用して、Scheppが提案したものと同じテクニックを作成しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
@container style(--scroll-direction: 0) { /* Scroll is idle, so we keep the current header position by setting the transition-delay to infinity */ header { transition-delay: calc(infinity * 1s); } } @container style(not (--scroll-direction: 0)) { /* page is scrolling: if needed, the animation of the header should run immediately */ header { transition-delay: 0s; } } @container style(--scroll-direction: -1) { /* Scrolling up, so we must reveal the header */ header { --translate: 0; } } @container style(--scroll-direction: 1) { /* Scrolling down, so we must hide the header */ header { --translate: -100%; } } |
これは素晴らしいです!
デモを試してみると分かると思いますが、100%完璧というわけではありません。スクロールダウンしてすぐにスクロールアップすると、ヘッダが隠れたままになることがあります。このことからScroll-Driven Animationsに頼るのではなく、ブラウザ自体がスクロール方向を表示する必要があることが分かりました。現在のところ、Scroll State Containerを使用することを考えています。
sponsors