JavaScriptで文字分割のアニメーション

どうも、くまだ です。

JavaScriptとSassをつかって、文字分割のアニメーションについて書いていきます。勉強したやつのアウトプットなので、オリジナルで考えたわけではありません。

今回使用する主なメソッドは、以下のメソッド。

  • split()
  • reduce()

文字分割のアニメーション htmlとSass

まずは完成版から。

これを作っていきます。最初にhtmlから。超カンタンな記述です。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link rel="stylesheet" href="css/style.css">
    <link href="https://fonts.googleapis.com/css2?family=Teko:wght@500&display=swap" rel="stylesheet">
</head>

<body>
    <div class="container">
        <div class="animation">
            アニメーション しますー。
        </div>
    </div>
    <script src="main.js"></script>
</body>

</html>

次にSassのコードを書きます。

.container {
  position: relative;
  height: 100vh;
}

.animation {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  opacity: 0;
  font-size: 24px;
  font-weight: bold;

  &.in {
    opacity: 1;
    
    .cat {
      display: inline-block;
      animation: cat_in 3s ease;
      animation-delay: 0;

      @for $i from 1 through 13 {
        &:nth-child(#{$i}) {
          animation-delay: $i * .06s;
        }
      }
    }
  }
}

@keyframes cat_in {
  0% {
    transform: translateY(-50%) rotate(-180deg);
    opacity: 0;
  }


  100% {
    transform: translate(0) rotate(360deg);
    opacity: 1;
  }
}

.in クラスはJavaScriptでクラスを付与させます。@keyframes cat_in でアニメーションの設定をしておきます。cat クラスは、JavaScriptでhtmlの文字を分割した文字一つ一つにあてるためのクラスです。

JavaScriptによって文章が1文字ずつに分割され、1文字ずつに.catクラスを付与。そしてcat_inアニメーションが入ります。

.catクラスが付与され、分割された文字はそれぞれ、@for文の記述のanimation-delayで0.06sずつ遅らせてアニメーションを動かします。

JavaScriptでも似たようなfor文(ループ処理)がありますが、それといっしょです。

@forの構文は以下のような記述です。

@for $変数名 from 開始値 through 終了値 {
// ここにスタイルをあてる処理を書く
}

もしくは、

@for $変数名 from 開始値 to 終了値 {

// ここにスタイルをあてる処理を書く

}

throughとto の違いは、

  • throughは、その数値を含める
  • to はその数値を含まない

以下は、参考記事です。

文字分割のアニメーション JavaScript

次にJavaScriptの記述を書いていきます。(\マークは、バックスラッシュに変換してください)

'use strict';

document.addEventListener('DOMContentLoaded',()=>{
  const elm = document.querySelector('.animation');
  elm.classList.add('in');

  const cut = elm.innerHTML.trim().split("");

  elm.innerHTML = cut.reduce((i, j) => {
    j = j.replace(/\s+/, '&nbsp;');//replace:置換
    return `${i}<span class="cat">${j}</span>`;

  }, "");

});

addEventListener メソッドは、イベントリスナー(イベントに合わせて実行させる関数)を登録するためのメソッドです。

DOMContentLoadedイベントは、HTMLの初期文章の読込が完全に読み込まれたタイミングで発生します。(スタイルシート、画像などの読込の完了は待たない)

document.querySelector で.animationを取得し、変数 elmに格納。

格納したelmに、classList.add でin クラスを付与。

classList は、特定のクラス名を追加・削除・参照することができるプロパティです。

使い方としては、上記のように classList.add(クラス名)みたいな感じでつかいます。classList関係で使えるものだと以下のようなものがあります。

  • add・・・クラス追加
  • remove・・・クラス削除
  • contains・・・クラスがあるか確認
  • toggle・・・クラスがあれば削除、なければ追加

変数elmを、innerHTMLで操作します。

innerHTMLは、HTML要素の中身を変更することができるプロパティです。trim()で空白を取り除き、splitメソッドで文字列を分割しています。

splitメソッドは、例えば以下みたいな感じで使うことができます。

const Arry = 'yamada taro';
const ret = Arry.split("");
console.log(ret);

これをコンソール画面で見ると、

文字分割

と、こんな感じで分割されます。

なので、elmをinnerHTMLによる操作によって、trim()によって空白を取り除き、splitで一文字ずつ分割してそれをcutに格納します。

そして次はreduceメソッドの部分ですが、以下のような構文で書きます。

reduce((累積値, 要素)={

});

例えば、reduce関数をつかって足し算をすると、

const num = [2,3,6,7,100];
const total = num.reduce((i,j)=>{
  return i + j;
});

console.log(total); // 118

このように、複数個の配列やオブジェクトをひとつにまとめる関数です。

例えば、上記のアニメーションを一文字ずつ分割してそれぞれspanタグで括りたいとします。すると下記のような感じで書きます。

const NewArry = mojiArry.reduce((x, y)=> {
  return `${x}<span>${y}</span>`;
});

console.log(NewArry);

これを検証ツールで確認すると、

spanタグで文字分割

分割された文字列にspanタグが挿入されています。

reduceメソッドの動きとしては、

〇1回目のループ:

 初期値がx(xの中身はyamada taroの y )。

 yにspanタグがつく(yの中身はyamada taro の a )。

〇2回目のループ:

xにはy<span>a</span>(1回目のループの結果)。

yにはspanタグがつく( yの中身はyamada taro の m )

〇3回目のループ:

xにはy<span>a</span><span>d</span>(2回目のループの結果)。

yにはspanタグがつく( yの中身はyamada taro の a )

以下、繰り返し。

そして、よく見ると最初の「y」がspanタグで括られていません。これを解決するためには、

const NewArry = mojiArry.reduce((x, y)=> {
  return `${x}<span>${y}</span>`;
}, '');

console.log(NewArry);

前と変わったのは、}); を、 }, ”);に変更しただけです。

スパンタグで文字分割

}, ”); の”には初期値を設定します。初期値に空文字を設定すると、上記のような処理になります。reduceメソッドの動きとしては、

〇1回目のループ:

 初期値がx(xの中身は、初期値の空白” )。

 yにspanタグがつく(yの中身はyamada taro の y )。

〇2回目のループ:

xには、空白<span>y</span>(1回目のループの結果)。

yにはspanタグがつく( yの中身はyamada taro の a )

〇3回目のループ:

xには、空白<span>y</span><span>a</span>(2回目のループの結果)。

yにはspanタグがつく( yの中身はyamada taro の m )

以下、繰り返し。

という感じになります。この要領で、<span class=”cat”></span>を挿入していきます。


elm.innerHTML = cut.reduce((i, j) => {
    j = j.replace(/\s+/, '&nbsp;');//replace:置換
    return `${i}<span class="cat">${j}</span>`;

  }, ""); //初期値は空

});

replaceに関しては、以下参考記事です。

というわけで、以下の処理を行うと、文字分割アニメーションをつくることができます。

ここまで読んでくださりありがとうございました。

この記事を書いた人