BLOG

【GASP】SplitTextを使ってテキストアニメーションを実装する

Written by mizuno

INDEX

Webサイトに「動き」を加える際に定番のJavaScriptライブラリのGSAP。
昨年より、運営体制がWeb制作プラットフォームのWebflowへと移行したことに伴い、商用利用を含めた全機能が無料で利用できるようになりました。

今回は、GSAPの人気プラグインの1つである「SplitText」についてご紹介します。

SplitText とは

指定したテキスト要素を解析し、その構造を自動的に書き換える機能を持ちます。
主に以下の単位で分割が可能です。

  • 文字単位 (chars):一文字ずつに分割。
  • 単語単位 (words): 単語ごとに分割。
  • 行単位 (lines): 改行位置を自動判別して行ごとに分割。

アクセシビリティも考慮されており、以下のような特徴があります。

  • テキストを分割しても、スクリーンリーダーなどの支援技術からは元の文章として正しく認識されるよう設計されています(親要素にaria-label 、子要素にaria-hiddenが自動で付与されます)
  • アニメーション完了後には元の要素へ戻すことも可能です

もう少し詳しく説明すると、下記のような要素があった場合、

<p class="word">あなたは犬派、それとも猫派ですか?</p>

SplitTextのcharsを実行すると、以下のように変換されます。

<p class="word" aria-label="あなたは犬派、それとも猫派ですか?"> // aria-labelが自動で付与
  <div aria-hidden="true"></div> // 子要素にaria-hiddenが自動で付与
  <div aria-hidden="true"></div>
  <div aria-hidden="true"></div>
  <div aria-hidden="true"></div>
  <div aria-hidden="true"></div>
  <div aria-hidden="true"></div>
  <div aria-hidden="true"></div>
  <div aria-hidden="true"></div>
  <div aria-hidden="true"></div>
  <div aria-hidden="true"></div>
  <div aria-hidden="true"></div>
  <div aria-hidden="true"></div>
  <div aria-hidden="true"></div>
  <div aria-hidden="true"></div>
  <div aria-hidden="true"></div>
  <div aria-hidden="true"></div>
  <div aria-hidden="true"></div>
</p>

アニメーション完了後は、以下のように元の状態へ戻すことが可能です。

<p class="word">あなたは犬派、それとも猫派ですか?</p>

通常、テキスト内に<div><span>が挿入されると、スクリーンリーダーの読み上げが遅くなる場合がありますが、本機能ではその点にも配慮されているのは嬉しいポイントです。

インストール

npmからインストールする場合

npm install gsap

読み込み方法

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

gsap.registerPlugin(SplitText);

CDNから読み込む場合

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js"></script> 
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/SplitText.min.js"></script>

サンプル

1文字ずつ浮き上がる動き

HTML

<p class="word">あなたは犬派、それとも猫派ですか?</p>

JavaScript

SplitText.create(".word", { // ".word"クラスの要素に対してSplitTextを適用
  type: "chars", // テキストを文字単位で分割
  onSplit(self) {
    return gsap.from(self.chars, {
      duration: 0.5,  // アニメーションの持続時間を0.5秒に設定
      y: 50, // Y軸方向に50px下から開始
      autoAlpha: 0, // 不透明度と表示状態を0(非表示)から開始
      stagger: 0.05, // 各文字のアニメーション開始を0.05秒ずつずらす
      onComplete: () => self.revert() // アニメーション完了時にSplitTextの分割を元に戻す
    });
  }
});

1行ずつ浮き上がる動き

HTML

<p class="word">あなたは犬派、それとも猫派ですか?<br>私は犬派です!</p>

JavaScript

SplitText.create(".word", {
  type: "lines", // テキストを行単位で分割
  mask: "lines", // 分割した行をマスクで囲む(オーバーフロー制御用)
  onSplit(self) {
    return gsap.from(self.lines, {
      duration: 0.8,
      y: 50,
      ease: "power2.out",
      stagger: 0.08,
      onComplete: () => self.revert()
    });
  }
});

スクロールに連動させる

HTML

<div class="container">
  <div class="block">
    <p class="scroll">SCROLL</p>
  </div>
  <div class="block">
    <p class="word">あなたは犬派、それとも猫派ですか?</p>
  </div>
  <div class="block">
    <p class="word">私は犬派ですね!</p>
  </div>
  <div class="block">
    <p class="word">いいですね!<br>どんなところが一番魅力だと思いますか?</p>
  </div>
</div>

※スクロールと連動させる場合は別途「ScrollTrigger」の読み込みが必要です

npmからインストールしている場合、下記を追加します。

import { gsap } from 'gsap'
import { SplitText } from "gsap/SplitText";
import { ScrollTrigger } from "gsap/ScrollTrigger"; // 追加する

gsap.registerPlugin(SplitText, ScrollTrigger) // 追加する

CDNから読み込む場合、下記をhead内に追加します。

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/ScrollTrigger.min.js"></script>

JavaScript


gsap.utils.toArray(".word").forEach((element) => { // ".word"クラスを持つ全ての要素を配列に変換し、各要素に対して処理を実行
  const split = new SplitText(element, {
    type: "lines",
    mask: "lines",
    onSplit(self) {
      return gsap.from(self.lines, {
        duration: 0.8,
        y: 50,
        ease: "power2.out",
        stagger: 0.1,
        scrollTrigger: { // スクロールに連動したアニメーションのトリガー設定
          trigger: self.elements, // アニメーションのトリガーとなる要素を指定
          start: "top 80%", // トリガー要素の上端がビューポートの80%の位置に来たときに開始
          markers: true // デバッグ用のマーカーを表示
        },
      });
    }
  });
});

タイピング風の動き

JavaScript

gsap.from(self.chars, {
  duration: 1.5,
  autoAlpha: 0, 
  ease: "steps(1)", // steps(1)を設定することでタイピング風の動きになる
  stagger: 0.05,
});

まとめ

まだまだ、動きの挙動を細かく制御できるオプションがたくさん用意されています。
表現の引き出しを増やすために、ぜひ公式サイトのドキュメントもチェックしてみてください。
以上、「SplitText」の紹介でした。

参考文献