本文へスキップ
HELLO!
HIGASHIYUKI®.COM
0   /   100
ナビゲーション

下へ読み進めるとヘッダーが隠れ、少し戻すと出る

デモ

操作:スクロール。 「さわってみる」を押すと自動再生が止まり、マウスで動かせます。 触っている間は、ホイールでデモの中がスクロールします。

仕様

動作
DOM
種類
レシピ
使うもの
ScrollTrigger
動作確認
three 0.186.0・gsap 3.15.0
公開日

しくみと調整

スクロールの向きだけを見て、下へ読み進めるあいだはヘッダーを上へ滑らせて隠し、少しでも上へ戻すと降ろします。向きは、スクロールのたびに前の位置と比べるのではなく、ScrollTrigger が持っている向きの値をそのまま読みます。

隠すときは 0.4 秒の power2.in、出すときは 0.45 秒の power3.out です。出すほうを強く減速させるのは、探し始めた人をできるだけ早く迎えるためで、隠すほうは気づかれない速さで足ります。動かす量はヘッダーの高さぶんで、下の縁の線まで画面の外へ出します。影を付けるなら、その影の分も足してください。

記事の冒頭を読んでいるあいだは隠しません。先頭でわずかに下へ動かしただけでヘッダーが消えると、ページが落ち着かなく見えるためです。冒頭の絵が画面の上へ抜けるところを、隠し始める線にしています。

向きが変わったときだけ、overwrite を付けたトゥイーンに置き換えます。スクロールのたびに作り直すと、前のトゥイーンと取り合ってヘッダーが小刻みに揺れます。メニューを開いているあいだや、ページ内のリンクで飛んだ直後は、出したまま止めておいてください。

長い記事・ドキュメント、画面の狭いスマートフォンのヘッダーに向いています。ヘッダーが画面の 5 分の 1 を占めるような場面ほど、返した場所が効きます。

コード

HTML
<header class="site-header">
  <a class="site-header__logo" href="/">Hi! I'm HIGASHIYUKI®</a>

  <nav class="site-header__nav" aria-label="カテゴリ">
    <ul>
      <li><a href="/culture/">Culture</a></li>
      <li><a href="/technology/" aria-current="page">Technology</a></li>
      <li><a href="/science/">Science</a></li>
      <li><a href="/design/">Design</a></li>
    </ul>
  </nav>

  <a class="site-header__cta" href="/subscribe/">購読する</a>
</header>

<article class="article">
  <h1 class="article__title">The quiet return of the slow web</h1>

  <!-- 冒頭の絵。ここが画面の上へ抜けるまでは、ヘッダーを隠さない -->
  <img class="article-lead" src="/img/slow-web.jpg" alt="" width="1600" height="900">

  <p>ポップアップが少なく、軽くて、最後まで読める文章。読む速さでWebを作り直す、小さな動きが広がっています。</p>
</article>
CSS
.site-header {
  --ink: #eeece6;
  --mute: #a8a6a0;
  --ground: #111111;
  position: fixed;
  inset: 0 0 auto;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 32px;
  box-sizing: border-box;
  height: 112px;
  padding: 0 6vw;
  /* 地はページと同じ色。影は付けず、下の縁だけ罫線で区切る */
  background-color: var(--ground);
  border-bottom: 1px solid rgba(238, 236, 230, 0.14);
  color: var(--mute);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.04em;
  white-space: nowrap;
}

.site-header a {
  color: inherit;
  text-decoration: none;
}

.site-header a:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 4px;
}

.site-header__logo {
  flex: none;
  margin-right: auto;
  font-size: 18px;
  font-weight: 700;
  letter-spacing: 0.12em;
  color: var(--ink);
}

.site-header__nav ul {
  display: flex;
  gap: 32px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-header__nav [aria-current="page"] {
  color: var(--ink);
}

.site-header__cta {
  flex: none;
  height: 40px;
  padding: 0 24px;
  border-radius: 999px;
  background-color: var(--ink);
  color: var(--ground);
  line-height: 40px;
}

/* 本文の先頭は、固定したヘッダーの分だけ空ける */
.article {
  max-width: 640px;
  margin: 0 auto;
  padding: 160px 6vw 144px;
}

.article__title {
  margin: 0 0 24px;
  font-size: clamp(28px, 3.4vw, 44px);
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -0.02em;
}

.article-lead {
  display: block;
  width: 100%;
  height: auto;
  margin-bottom: 48px;
  border-radius: 4px;
}
JavaScript
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";

gsap.registerPlugin(ScrollTrigger);

const header = document.querySelector(".site-header");
const lead = document.querySelector(".article-lead");
const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;

// 動きを減らす設定では、ヘッダーを出したままにする
if (header && !reduceMotion) {
  let hidden = false;

  const setHidden = (next) => {
    // 向きが変わったときだけ作る。スクロールのたびに作ると、前のトゥイーンと取り合って揺れる
    if (next === hidden) return;
    hidden = next;
    gsap.to(
      header,
      next
        ? // 下の縁の線まで画面の外へ出す(影を付けるなら、その分も足す)
          { y: -header.offsetHeight, duration: 0.4, ease: "power2.in", overwrite: true }
        : { y: 0, duration: 0.45, ease: "power3.out", overwrite: true }
    );
  };

  ScrollTrigger.create({
    // 冒頭の絵が画面の上へ抜けるまでは隠さない(先頭からの量で決めるなら start: 100)
    trigger: lead ?? document.body,
    start: lead ? "bottom top" : 100,
    end: "max",
    onUpdate: (self) => setHidden(self.direction === 1), // 下へ送ると 1、上へ戻すと -1
    onLeaveBack: () => setHidden(false), // 冒頭まで戻ったら出したまま
  });

  // メニューを開いているあいだや、ページ内リンクで飛んだ直後は setHidden(false) で出したままにする
}

インタラクションデザインについて、
お気軽にご相談ください。

ここに並べているのは、Web サイトの中で動く UI のサンプルです。新しく作るサイトに組み込むことも、いま公開中のサイトに、ボタンやヒーロー、スクロールの演出だけを足すこともできます。設計から実装までの進め方はWeb サイト制作、端末ごとの見え方や表示速度の考え方はレスポンシブウェブサイトのページにまとめています。映像として作る動きをお探しの場合はモーショングラフィックスをご覧ください。