Textillin とは

tlt-fadeInBottom などのクラスを付けるだけで、テキストを1文字ずつアニメーションさせるライブラリです。スクロールで要素がビューポートに入ったタイミングで自動実行されます。

<strong class="tlt-bounceInBottom">
  <span>文字が1文字ずつ下からバウンスしてきます。</span>
</strong>

特徴:

  • Vanilla JS — jQuery不要
  • IntersectionObserver API — スクロール監視にネイティブAPIを使用
  • MutationObserver 対応 — 動的に追加された要素も自動検出
  • [untextillin] 属性 — 特定セクション内のアニメーションを無効化できる
  • @media print 対応 — FireShot等のスクリーンショットで正常にキャプチャされる
  • .delayed-* / .fasted-* / .slowed-* でタイミング調整可能

使い方

1. ファイルを読み込む

<link rel="stylesheet" href="textillin.css">
<script src="textillin.js"></script>

2. tlt-エフェクト名 クラスと <span> でテキストを囲む

<h2 class="tlt-fadeInBottom">
  <span>スクロールで文字が1文字ずつフェードイン</span>
</h2>

<strong> / <h2> / <p> 等の要素に tlt-* クラスを付け、テキストを <span> で囲むだけです。スクロールで要素がビューポートに入ったタイミングで自動的にアニメーションが実行されます。


利用可能なエフェクト一覧

クラス名効果
tlt-fadeIn1文字ずつフェードイン
tlt-fadeInBottom下から1文字ずつフェードイン
tlt-fadeInTop上から1文字ずつフェードイン
tlt-fadeInLeft左から1文字ずつフェードイン
tlt-fadeInRight右から1文字ずつフェードイン
tlt-bounceIn1文字ずつバウンスイン
tlt-bounceInBottom下から1文字ずつバウンスイン
tlt-bounceInTop上から1文字ずつバウンスイン
tlt-bounceInLeft左から1文字ずつバウンスイン
tlt-bounceInRight右から1文字ずつバウンスイン
tlt-flipIn1文字ずつフリップ(3D回転)
tlt-flipInXX軸方向に1文字ずつフリップ
tlt-flipInYY軸方向に1文字ずつフリップ
tlt-flashIn1文字ずつフラッシュ(点滅)
tlt-shakeIn1文字ずつシェイク
tlt-pulseIn1文字ずつパルス(拡縮)
tlt-rollIn1文字ずつ横からロール

data-* 属性によるカスタマイズ

文字の登場順序

<!-- シャッフル(ランダム順)で登場 -->
<strong class="tlt-fadeInBottom">
  <span data-in-shuffle="true">ランダムに登場します</span>
</strong>

<!-- 逆順で登場 -->
<strong class="tlt-bounceInBottom">
  <span data-in-reverse="true">右端から登場します</span>
</strong>

<!-- 全文字同時に登場(1文字ずつでなく一斉) -->
<strong class="tlt-fadeIn">
  <span data-in-sync="true">全文字が同時にフェードイン</span>
</strong>

文字間のディレイ

<!-- 文字間のディレイを広くする(デフォルト30ms) -->
<strong class="tlt-fadeInBottom">
  <span data-in-delay="60">ゆっくり1文字ずつ登場</span>
</strong>

ループ再生と複数テキストの切り替え

<strong class="tlt-fadeIn" data-loop="true" data-minDisplayTime="2000">
  <ul class="texts">
    <li>最初のテキスト</li>
    <li>次のテキスト</li>
    <li>最後のテキスト</li>
  </ul>
</strong>

data-loop="true" を付けると、複数の <li> テキストがアウト→インを繰り返します。data-minDisplayTime で各テキストの表示時間(ms)を指定できます。


タイミング調整クラス

<!-- 0.5秒遅れて開始 -->
<strong class="tlt-fadeInBottom delayed-2">
  <span>テキスト</span>
</strong>

<!-- ゆっくり(2秒かけて)アニメーション -->
<strong class="tlt-bounceInBottom slowed-2">
  <span>テキスト</span>
</strong>

ディレイ(.delayed-*

クラス遅延
delayed-00s
delayed-10.25s
delayed-20.5s
delayed-30.75s
delayed-41s
delayed-51.25s
delayed-61.5s

速度調整

クラス再生時間
fasted-10.75s
fasted-20.5s
fasted-30.25s
slowed-11.5s
slowed-22s
slowed-33s
slowed-55s

アニメーションを無効化する([untextillin]

祖先要素に untextillin 属性を付けると、その配下のテキストアニメーションをすべて無効化できます。

<section untextillin>
  <strong class="tlt-fadeInBottom">
    <span>アニメーションせず即表示される</span>
  </strong>
</section>

CSSでは :not([untextillin]) を使って animation-nameanimation-duration を無効化します。JSでは el.closest('[untextillin]') でチェックし、アニメーションをスキップして即 visibility: visible にします。これにより animationend イベントが発火しない問題も回避しています。


JavaScript API

// 手動でアニメーションを実行
TextillinOptimized.trigger(element, 'fadeInBottom');

// カスタムエフェクトを追加
TextillinOptimized.addEffect('myEffect', 'myCssClass');

// 統計情報
TextillinOptimized.getStats();
// → { registeredTypes: [...], observedCount: 3, animatedCount: 10, availableEffects: 17 }

// デバッグモード(コンソールにアニメーション情報を出力)
TextillinOptimized.enableDebug();

// 破棄(Observer切断・メモリ解放)
TextillinOptimized.destroy();

Textillate・Lettering.js との関係

Textillin は内部的に以下の実装を Vanilla JS に移植して使用しています。

  • Textillate.js by Jordan Schroter (MIT License) — テキストアニメーションのオーケストレーション
  • Lettering.js by Dave Rupert (WTFPL) — テキストを1文字ずつ <span> に分割
  • Animate.css by Daniel Eden (MIT License) — アニメーションのキーフレーム定義

これらを組み合わせ、jQueryへの依存をなくし、IntersectionObserver によるスクロールトリガーを追加したものが Textillin です。


実装の仕組み

  1. ページ読み込み時に tlt-* クラスを持つ要素を検出し IntersectionObserver に登録
  2. ビューポートに10%以上入ったとき(下端から50pxのマージンあり)にアニメーション発火
  3. テキストを1文字ずつ <span> に分割し、各文字に順番にアニメーションを適用
  4. アニメーション済みの要素は監視解除(一度きり)
  5. MutationObserver で動的に追加された要素も自動検出・登録

対応ブラウザ

  • Chrome 51+
  • Firefox 55+
  • Safari 12.1+
  • Edge 15+

@media print / FireShot 対応

Textillin のエフェクトは animation ベースのため、FireShot など印刷エンジンを使うキャプチャツールでは文字が初期状態(不可視)のままになる問題があります。@media print ブロックで対処済みです。

@media print {
  [class*="tlt-"] {
    animation: none !important;
    opacity: 1 !important;
    visibility: visible !important;
  }
}