本文へスキップ
HELLO!
HIGASHIYUKI®.COM
0   /   100
ヒーロー

散らばった文字が集まって見出しになる

デモ

仕様

用途
ヒーロー
動作
DOM
種類
レシピ
使うもの
SplitText
動作確認
three 0.186.0・gsap 3.15.0
公開日

しくみと調整

散らばった文字が、回りながら集まって見出しに組み上がります。見出しを1文字ずつに分け、散らばった位置・角度・大きさ・濃さをあらかじめ決めてから、元の位置へ戻すトゥイーンとして書いています。散らばる先は画面を格子に割って1文字1マスずつ振り分け、マスの中で少しだけずらしています。ただの乱数で位置を決めると文字どうしが固まり、空いた場所ができてしまうためです。

集まる時間は1.6秒、power3.inOutで勢いよく寄ってきて静かに収まります。文字ごとの遅れは、順番を混ぜてから均等に配っているので、決まった並びではなく思い思いに集まって見えます。奥行きを出すため、小さく散った文字ほど薄くしています。

薄くしすぎると、明るい色の文字が暗い地と混ざってくすんで見えます。濃さは半分より下げないようにしています。文字を動かす指定は、回転や拡大とあわせても画面が乱れないよう、2D の変形だけで組んでいます。

つまみは散らばる範囲・マスの中のずれ幅・回転の最大角・時間です。範囲を広げるほど、組み上がる瞬間の勢いが強く見えます。ブランドサイトのヒーローや、スライドの切り替えなど、画面全体を使って印象づけたい場面に向いています。

コード

HTML
<section class="scatter-hero">
  <h2 class="scatter-hero__title">ばらばらの想いを、<br>ひとつに。</h2>
  <p class="scatter-hero__lead">ここに説明文が入ります。</p>
</section>

CSS
.scatter-hero {
  display: grid;
  align-content: center;
  justify-items: center;
  gap: 20px;
  min-height: 70vh;
  padding: 96px 6vw;
  overflow: clip;
  background: #111111;
  color: #eeece6;
  text-align: center;
}

.scatter-hero__title {
  margin: 0;
  font-size: clamp(30px, 9vw, 96px);
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -0.02em;
}

.scatter-hero__lead {
  max-width: 34em;
  margin: 0;
  font-size: 18px;
  line-height: 1.8;
  letter-spacing: 0.04em;
  word-break: keep-all; /* 和文は <wbr> を書いた文節の切れ目でだけ折り返す */
  color: #a8a6a0;
}

JavaScript
import { gsap } from "gsap";
import { SplitText } from "gsap/SplitText";

gsap.registerPlugin(SplitText);

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

// 字形が確定してから分割する(あとでフォントが差し替わると文字位置がずれる)
document.fonts.ready.then(() => {
  document.querySelectorAll(".scatter-hero").forEach((section) => {
    const title = section.querySelector(".scatter-hero__title");
    const lead = section.querySelector(".scatter-hero__lead");
    const split = SplitText.create(title, { type: "chars" });
    const r = gsap.utils.random;

    const assemble = gsap
      .timeline({ paused: true })
      .from(split.chars, {
        x: () => r(-260, 260),
        y: () => r(-130, 130),
        rotation: () => r(-140, 140),
        scale: () => r(0.45, 1.15),
        opacity: 0.5,
        duration: 1.6,
        ease: "power3.inOut",
        stagger: { each: 0.04, from: "random" },
        force3D: false,
      })
      .from(lead, { autoAlpha: 0, y: 24, duration: 0.8, ease: "power2.out" }, 0.9);

    if (reduceMotion) {
      assemble.progress(1);
      return;
    }

    // 画面に入ったら 1 回だけ組み上げる
    const io = new IntersectionObserver(
      (entries, self) => {
        for (const entry of entries) {
          if (!entry.isIntersecting) continue;
          self.unobserve(entry.target);
          assemble.play();
        }
      },
      { rootMargin: "0px 0px -15%" }
    );
    io.observe(section);
  });
});

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

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