フーノページ





JavaScirptで1文字ごとのアニメーションを自動化。










JavaScriptで一気に編集。


こんにちは、「ふ」です。
テキスト要素を1文字ずつアニメーションさせたい場合。

<p>TEXT</p>

TEXT

<p>などのテキスト要素自体にアニメーションを掛けると、⬆︎のように要素全体がアニメーションしてしまいます。文字単位でアニメーションさせたい場合には、1文字ずつ<span>タグなどでマークアップして参照できるようにする必要があります。

<p>
<span>T</span>
<span>E</span>
<span>X</span>
<span>T</span>
</p>

⬆︎のようにしてCSSでセレクトし、アニメーションを施すことになります。
しかしながら。手動で1文字ずつマークアップしていくのも骨が折れるというもの💧

そこで今回はJavaScriptを使って自動でテキストを1文字ずつマークアップ→アニメーションさせるところまでやってみましょう。記事の後半では一連の処理を関数化し、汎用性を持たせたサンプルも紹介します。

1文字ずつ<span>で囲む。


<p id = "sample">ABCDE</p>

ABCDE

テキスト要素を用意しました。
JavaScriptでテキストを1文字ずつ取得し、<span>〜</span>で囲んでいきます。

「「3//要素を取得」」「「1 ..@1@」」
const sample = document.getElementById("sample");

「「3//変換後のHTMLをここに配置」」「「1 ..@2@」」
let inner = "";

「「3//1文字ずつ処理をする」」「「1 ..@3@」」
for(i=0;i<sample.innerText.length;i++) {

    「「3//<span>〜</span>で囲み、innerに追加」」「「1 ..@4@」」
    inner += `<span>${sample.innerText[i]}</span>`
}

「「3//sampleのHTMLを変更」」「「1 ..@5@」」
sample.innerHTML = inner;

@1@ <p>要素を取得。

@2@ 変換後のHTMLコードをいったん、この変数innerに収めます。

@3@ for文で1文字ずつ取り出して処理をしましょう。sample.innerTextで取り出したものは文字列(string)ですが、配列のようにインデックスで1文字ずつ取り出すことができます。

@4@ 取り出した文字を<span>〜</span>で囲み、先ほどの変数innerに追加していきます。

@5@ ループ処理で各文字の変換が終わったら、要素sampleの内容を書き換えます。




console.log(sample);
「「3▶︎ <p id = "sample">
    <span>A</span>
    <span>B</span>
    <span>C</span>
    <span>D</span>
    <span>E</span>
  </p>」」

処理後の#sampleの内容を出力してみました。
ちゃんと1文字ずつマークアップされていますね。

JavaScriptのテンプレートリテラル

JavaScriptのドルマーク$に中括弧{ }、テンプレートリテラルについて。

〽️ クオテーション祭り、さようなら。




スタイルを付与。


マークアップされたそれぞれの文字に渡すアニメーションを、CSSで用意しました。

.each {
    display:inline-block;「「1 ..@1@」」
    animation:each 2s linear infinite;
}

@keyframes each {
    50% {transform:rotate(1turn);}
    to {transform:rotate(1turn)}
}

キーフレームの50%で1回転するアニメーションにしています。

アニメーションを指定するついでに、@1@の部分でdisplayの指定をしています。
<span>はもともとインライン要素です。 インライン要素のテキストは、CSSアニメーションを指定しても動いてくれません。そこでdisplay:inline-blockとし、インラインブロック要素に変更しておきましょう。

アニメーションが用意できたら、「each」クラスをそれぞれの<span>要素に付与していきましょう。
各要素へのアクセスは親要素sampleの子要素(children)として、取り出すことにしました。

for(i=0;i<sample.children.length;i++){
    sample.children[i].classList.add("each");
    }

ABCDE

各文字が独立してアニメーションしています。
いい感じですね。

時間差攻撃。


せっかくなので(←何が?)、それぞれの文字のアニメーションに時間差をつけてみましょう。
それぞれの<span>要素に、値を変化させたanimation-delayを指定します。 先ほどのfor文にそのまま追記。

for(i=0;i<sample.children.length;i++){
    sample.children[i].classList.add("each");
    sample.children[i].style.animationDelay = `${i*0.2}s`
    }

時間差の値には、子要素のindexを利用しました。インデックスは「0,1,2..」と増えていくので、それに0.2を掛けて「0.0,0.2,0.4..」とanimation-delayを指定していきます。

ABCDE

各文字が0.2秒ずつ時間差でアニメーションするようになりました。
「独立感」が引き立ちましたね。

CSS animation-delay

CSSアニメーション、animation-delay。

〽️ アニメーションの時間差攻撃。




関数にしてしまいました。


ここまでの処理を関数定義にし、引数入力のみで「文字ごとのアニメーション」が実装できるようにしてみました。

「「3//要素/クラス/時間差を引数に」」「「1 ..@1@」」
function each_letter(「「5element,cls,delay」」) {

    「「3//要素はidで取得。」」「「1 ..@2@」」
    const elm = document.getElementById(element);
    let inner = "";
    for(i=0;i<elm.textContent.length;i++) {
        inner += `${elm.textContent[i]}`;
    }
    elm.innerHTML = inner;

    for(i=0;i<elm.children.length;i++) {
        elm.children[i].classList.add(cls);

        「「3//displayプロパティの変更もここにした。」」「「1 ..@3@」」
        elm.children[i].style.display = "inline-block";

        「「3//時間差の入力は任意」」「「1 ..@4@」」
        if(delay) {
            elm.children[i].style.animationDelay = `${i*delay}s`;
        }
    }
}

@1@ 関数each_letterを作成。引数のところに要素/付与するCSS/時間差を入力できるようにしています。

@2@ アニメーションさせたい要素には、id名をつけて参照させることとします。

displayプロパティの変更処理。先ほどは付与するCSSの中に含めていましたが、それも関数内に組み込んであります。

@4@ 時間差の入力は任意ということにします。そのためdelay処理は条件文を使いました。

その他の処理は、これまでのものと同じです。
要素とアニメーションのCSSを用意し、試してみましょう。

<p id = "auto_ani">ABCDE</p>

要素にはid名をつけておいてください。

.scale {
    animation:scale 2s linear alternate infinite;
}
@keyframes scale {
    from {transform:scale(0.1);}
}

アニメーションは、大きさを変化させるものにしました。
それでは関数をつかってみます。

each_letter("auto_ani","scale",0.1);

ABCDE

引数指定した関数を実行するだけで「1文字ずつアニメーション」が実装できました。
これは便利です。

最後までお読みくださり、ありがとうございました
今後も面白いチュートリアルができたら、紹介していこうと思います。

ではまた〜 ♪





「ふ」です。

ふ

ベクターグラフィック、web、ガジェットなど。役立つ情報や観ていてたのしいページを書いていきたいと思います。