本文へスキップ
HELLO!
HIGASHIYUKI®.COM
0   /   100
セクション

スクロールでセクションの大きな文字が左から塗られていく

デモ

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

仕様

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

しくみと調整

SplitText で文章を行に分け、行ごとに、塗る色のグラデーションを背景に敷いて文字の形で切り抜きます(background-clip の text)。各行の幅は文字に合わせておきます。背景の幅を 0% から広げていくと、文字が左から塗られていきます。

背景の幅を 0% から 100% へ、イーズ無しで伸ばします。行ごとに 1 つずつ順に始めると、上の行から順に塗られます。結びつけるのは ScrollTrigger で、文章の上端が画面の高さの 80% に来たら始まり、下端が 45% に来たら塗り終わる範囲を、スクロール量にそのまま連動させます(scrub)。1 文字ずつ色を変える方式と違い、行の途中まで塗られた状態を出せます。

background の一括指定は切り抜きの指定を初期値に戻すので、切り抜きは一括指定の後に書きます。行の幅は字形で決まるので、行に分けるのは、書体の読み込みが終わってからにします。

和文は空白で語に分かれないため、そのままでは全体がひとかたまりの行になります。文節の切れ目に <br> を入れて、行を決めてください。改行の文字や、改行を活かす white-space の指定では、行がまとまってしまいます。

コード

HTML
<section class="fill-section">
  <p class="fill-eyebrow">Our approach</p>

  <!--
    和文は空白で語に分かれないので、文節の切れ目に <br> を入れて行を決める。
    SplitText は <br> で行を分ける(英文なら <br> は要らず、幅で折り返した行に分かれる)。
  -->
  <p class="fill-text">気づくより先に、心で感じる。<br>
    そんな動きをデザインしています。<br>
    静かに、正確に、そしていつも<br>
    伝えたい物語のために。</p>
</section>
CSS
.fill-section {
  --dim: #343433; /* 塗る前の文字の色(地に文字の色を少し混ぜた暗い灰色) */
  --fill: #eeece6; /* 塗った後の文字の色 */
  padding: 40vh 6vw 22vh;
  background-color: #111111;
}

.fill-eyebrow {
  margin: 0 0 24px;
  font-size: 13px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #a8a6a0;
}

/* JS が動かないときは、ふつうの読める文字のまま(切り抜きは分割した後にだけ効かせる) */
.fill-text {
  margin: 0;
  font-size: clamp(28px, 4.4vw, 56px);
  font-weight: 700;
  line-height: 1.5;
  letter-spacing: 0.04em;
  color: var(--fill);
}

/* SplitText が作る行。塗る範囲を文字の幅にそろえ、背景を文字の形で切り抜く */
.fill-text.is-split .line {
  width: fit-content;
  color: transparent;
  background: linear-gradient(var(--fill), var(--fill)) 0 0 / 0% 100% no-repeat, var(--dim);
  -webkit-background-clip: text;
  /* 一括指定(background)は切り抜きを初期値に戻すので、必ずその後に書く */
  background-clip: text;
}
JavaScript
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { SplitText } from "gsap/SplitText";

gsap.registerPlugin(ScrollTrigger, SplitText);

const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;

// 行の幅は字形で決まるので、書体の読み込みが終わってから行に分ける
document.fonts.ready.then(() => {
  document.querySelectorAll(".fill-text").forEach((text) => {
    const split = SplitText.create(text, { type: "lines", linesClass: "line" });
    text.classList.add("is-split"); // ここで初めて、文字の形で切り抜く見た目にする

    // 動きを減らす設定では、塗り終わった状態で止めておく
    if (reduceMotion) {
      gsap.set(split.lines, { backgroundSize: "100% 100%" });
      return;
    }

    gsap.fromTo(
      split.lines,
      { backgroundSize: "0% 100%" },
      {
        backgroundSize: "100% 100%",
        ease: "none",
        duration: 1,
        stagger: 1, // 1 行ずつ順に塗る
        scrollTrigger: {
          trigger: text,
          start: "top 80%", // 文章の上端が画面の高さの 80% に来たら塗り始める
          end: "bottom 45%", // 下端が 45% に来たら塗り終わる
          scrub: true, // スクロール量にそのまま連動させる(数値の scrub は実時間で追うので使わない)
        },
      }
    );
  });
});

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

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