JavaScript

一文字ずつのテキストアニメーションを途中にタグがあってもJavaScriptとCSSで実装

長いタイトルですみません。
しかしながらもう一度(※)、さらに補足も加えて言うと、

「凝ったテキストアニメーションのために1文字ずつspanで囲むことを、途中にHTMLのタグがあってもJavaScriptで実装する方法(jQueryなし)」

をご紹介します。

例えば全てのh2要素に同じテキストアニメーションをつけるといったことをしたくなると思うのですが、見出し要素は、

<h2>BringFlower<br><span class="sub">ブリングフラワー</span><h2>

のように、br要素(タグ)やspan要素(タグ)をつけることがあると思います。その場合でも動く、というのが一つのポイントです。

※ちなみに私はSEO対策でタイトルたまに変えるので、画像のタイトル表記とここでの表記が異なっている可能性はありますがご承知おきください。

実現できるアニメーション例

これからご紹介するJavaScriptの実装を行うことで実現できるアニメーション例をまずひとつお示しします。

BringFlower
ウェブで広げる、繋がる。

※2回目以降再生する場合はリセットボタンを押してから再生ボタンを押してください。

アニメーション例の解説

  • 1文字ずつspan要素で囲って、animation-delayプロパティで1文字目より2文字目が0.1秒遅いアニメーション、2文字目はそれよりさらに0.1秒遅いアニメーションが動く、というように、1文字ごとに0.1秒ずつ遅くアニメーションが動くようにしてあります。
  • :nth-child(even)nth-child(odd)を使って、奇数番目の文字と偶数番目の文字で、初期位置とアニメーションの動く方向を変えています。

つまりアニメーション自体は、HTMLとCSSだけで実現しています。
なので1箇所だけなら最初からHTMLとCSSをそのように書けばよいですが、多くの個所、例えば全ての見出し要素に同じこういったアニメーションをつけるとなると、現実的ではありません。

JavaScriptでの実装

特定の要素(この例ではtextAnimaとクラス名が付けられた要素)の中に入っている文字を1文字ずつspan要素で囲い、かつstyle属性でanimation-delayプロパティもつけるというのが次のJavaScriptです。

ここでポイントが、特定の要素の中に<br><span>などのタグが入っていても動作させているということです。それがなくて、かつjQueryでよければ、紹介されているサイトはあります。

また、1文字ごとに異なるスタイルを当てやすいように、char c-01, char c-02というようにクラス名も個別につけています。

function spanWrap() {
  const targets = document.querySelectorAll('.textAnima')
  targets.forEach( function (target) {
      let nodes = [...target.childNodes];
      let textBox = '';
      nodes.forEach( function (node) {
      if (node.nodeType == 3) { //テキストの場合
          let text = node.textContent.replace(/\r?\n/g, ''); //テキストから改行コード削除
          text.split('').forEach(function (t, i) {
              if (t !== " ") {
                if (i < 10) {
                  textBox += '<span class="char c-0' + (i + 1) + '" ' + 'style="animation-delay:.' + i + 's;">' + t + '</span>';
                } else {
                  let n = i / 10;
                  textBox += '<span class="char c-0' + (i + 1) + '" ' + 'style="animation-delay:' + n + 's;">' + t + '</span>';
                }
              } else {
                textBox += t;
              }
            });
      } else if (node.contains(node) == true) { // テキストではなく、子ノード(=span要素)を持つ
          // そのまま連結
          textBox = textBox + node.outerHTML;
      } else { // テキストではなく、br要素などspan要素以外の要素を持つ
          // そのまま連結 ※br要素などをspan要素とは別に処理する場合はここに書く
          textBox = textBox + node.outerHTML;
        }
      })
      target.innerHTML = textBox
  })
}
spanWrap();

デモその2

こちらも再生ボタンを押してみてください。最初のデモのCSSアニメーションに対して、opacity: 0からopacity: 1への変化を加えたのと、回転を加えただけです。

こうやって色々遊べると思うので、この記事をきっかけに面白いアニメーション作れた方は問い合わせフォームからそのソースコードを連絡ください。

BringFlower
ウェブで広げる、繋がる。

※2回目以降再生する場合はリセットボタンを押してから再生ボタンを押してください。

まとめ

1文字ずつ動かすテキストアニメーションの作り方、いかがでしたでしょうか?

著者のイメージ画像

株式会社BringFlower
稲田 高洋(Takahiro Inada)

2003年から大手総合電機メーカーでUXデザインプロセスの研究、実践。UXデザイン専門家の育成プログラム開発。SEOにおいても重要なW3Cが定めるWeb標準仕様策定にウェブアクセシビリティの専門家として関わる。2010~2018年に人間中心設計専門家を保有、数年間ウェブアクセシビリティ基盤委員も務める。その後、不動産会社向けにSaaSを提供する企業の事業開発部で複数サービスを企画、ローンチ。CMSを提供し1000以上のサイトを分析。顧客サポート、サイト運営にも関わる。
2022年3月に独立後、2024年4月に株式会社BringFlowerを設立。SEOコンサルを活動の軸に据えつつ、AIライティングツールの開発と運営を自ら行う。グッドデザイン賞4件、ドイツユニバーサルデザイン賞2件、米国IDEA賞1件の受賞歴あり。