JavaScript - タイプライター風に一文字ずつ表示する方法

タイピングアニメーションを作ろう

今回紹介するのは、JavaScript で作るタイピングアニメーションです。タイプライター風に文字を一つずつ増やしながら表示するだけでなく、削除キーで文字を消去する様子も表現します。

この記事を読むと分かること

  • slice()
  • if...else
  • setTimeout()

サンプルプロジェクト

最初に、タイピングアニメーションの動きを確認しておきましょう。文字入力の様子をよりリアルにするために、文字を表示するときはランダムな速さにして、消去するときは一定のスピードで消えていくようにしています。

ライプライター風アニメーションのサンプルプロジェクト

HTML

まずは HTML です。文字を表示するスペースを <p> 要素で用意しておきます。表示する文字列はこのあと JavaScript で指定しますよ。

<p class="typingText"></p>

CSS

続いて CSS です。文字の後ろに表示するカーソルは CSS で作ります。カーソルを点滅させるアニメーションも設定しましょう。

.typingText {
  font-size: 50px;
  color: white;
  text-align: center;
}

/*文字の後ろにカーソルを追加*/
.typingText::after {
  content: "|";
  color: white;
  animation: blink 1s infinite; /*カーソル点滅アニメーション*/
}

/*カーソル点滅アニメーションの定義*/
@keyframes blink {
  0%, 100% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }    
}

ここまでで、ブラウザには点滅するカーソルのみが表示されています。次のセクションからは、JavaScript で文字列を表示していきますよ。

JavaScript

先ほど、HTML で文字を表示するスペースを作っておきましましたね。ここに JavaScript で文字列を表示していけるように、要素を取得しておきましょう。

// 要素の取得
const typingText = document.querySelector('.typingText');

表示する文字列を用意します。

// 文字列を用意
const text = 'Welcome to Pyxofy!';

一文字ずつ表示するためには、インデックス番号で文字を一つずつ順番に指定します。 変数 index を用意して、1 で初期化しておいてください。

// インデックスを1で初期化
let index = 1;

一文字ずつ表示する関数

ではこれから、一文字ずつ表示する関数を定義してきますよ。ここでは、関数名を typeText とします。

// 一文字ずつ表示する関数
function typeText() {
 
  // 一文字ずつ表示する処理
  // …

}

次の手順でコードを書いていきましょう。

  1. 文字列の範囲を指定して表示する
  2. 文字を追加するか消去するか処理を分ける
  3. 一文字追加してランダムな間隔で表示する
  4. すべての文字が表示されたら文字を消去する関数へ移る

文字列の範囲を指定して表示する

まずは、用意した文字列のどこからどこまでを表示するかを決める文を書きます。文字列の範囲を指定するために使うのは、slice() メソッドです。slice() の括弧 () の中に文字の位置(インデックス)を指定すると、文字列の一部を抜き出すことができます。

構文:

文字列.slice(最初のインデックス, 最後のインデックス) //最後のインデックスは含まれない

文字列のインデックスは 0 から始まる、ということに注意してくださいね。括弧 () に指定する最後のインデックスは、省略することもできますよ。

slice() メソッドの例:

const hiragana = 'あいうえお';

hiragana.slice(0, 1) // あ
hiragana.slice(0, 3) // あいう
hiragana.slice(0)    // あいうえお
hiragana.slice(4)    // お
hiragana.slice(0, hiragana.length) // あいうえお

では、文字列 text の一部を抜き出すコードを書いていきましょう。

  • 最初のインデックスは 0
  • 最後のインデックスは、変数 index を指定して更新されるようにする
// 最初の文字〜変数indexまでの文字を抜き出す
text.slice(0, index);
  • text.slice(0, index) で返る文字列を、取得した HTML 要素の textContent プロパティに代入して表示する
function typeText() {
 
  // 最初の文字〜変数indexまでの文字列を表示する
  typingText.textContent = text.slice(0, index);

}

変数 index1 で初期化したので、最初は一番初めの文字のみが表示されますよ。以上で、文字列の範囲を指定して表示するコードができました。

文字を追加するか消去するか処理を分ける

次は、 if...else 文です。変数 index の値によって、文字を追加するか消去するか、処理を分けます。

  • 変数 index が文字列の長さ text.length より小さい、つまり、まだ表示されていない文字があるなら文字を追加する
  • すべての文字が表示されたら、文字を消去する処理を行う
function typeText() {
  typingText.textContent = text.slice(0, index);

  // もしまだ表示されていない文字があるなら
  if (index < text.length) {
 
    // 一文字ずつ追加する処理
    // …

  } else { // すべての文字が表示されたら
 
    // 一文字ずつ消去する処理
    // …

  }
}

一文字追加してランダムな間隔で表示する

if 文の条件が満たされている間は、まだ表示されていない文字が残っているので、一文字追加します。

  • 変数 index の値を1増やす
function typeText() {
  typingText.textContent = text.slice(0, index);
  if (index < text.length) {

    // 変数indexを1増やす(文字を一つ追加する)
    index++;

  } else { 
    // …
  }
}

変数 index を1増やして一文字追加したら、その文字列を表示するために、setTimeout() メソッドで関数 typeText を呼び出します。setTimeout() は、指定した時間が経過した後に関数を実行するメソッドです。

構文:

setTimeout(関数, 遅延時間)

遅延時間は数値で指定できますが、ここでは Math.random() メソッドを利用して乱数を指定しますよ。タイピング効果をよりリアルにするために、文字を表示するタイミングをランダムにするためです。

  • 乱数を生成して、変数 randomInterval に格納する
  • ランダムな時間待ってから関数 typeText を実行する
function typeText() {
  typingText.textContent = text.slice(0, index);
  if (index < text.length) {
    index++;

    // 乱数を生成
    const randomInterval = Math.floor(Math.random() * 350) + 50;
    // 一文字ずつ表示する関数をランダムな時間待ってから実行する
    setTimeout(typeText, randomInterval);

  } else {
    // …
  }
}

if 文の条件が満たされている間は、一文字ずつ追加して、ランダムな間隔で文字列を表示するコードができました。

乱数については以下の記事で詳しく解説しているのでご覧ください。

JavaScript - 乱数の作り方とランダムな色を生成するコード
JavaScript の Math.random() と Math.floor() メソッドを利用して乱数を生成する方法を紹介します。乱数を使って RGB カラーをランダムに表示する簡単なプロジェクトも掲載しているので、ぜひご覧ください。

すべての文字が表示されたら文字を消去する関数へ移る

続いて、 else の部分を書いていきましょう。 if (index < text.length) の条件が満たされなくなるのは、すべての文字が表示されたときですね。文字の追加をストップして、文字を消去する関数をスタートしますよ。

文字の消去を始めるために、ここでも setTimeout() メソッドを使って関数を呼び出します。すべての文字が表示されたあとすぐに消去を始めるのではなく、少し待ってから消えていくようにするためです。指定する関数 eraseText は、一文字ずつ消去する関数で、このあと定義していきます。

  • 遅延時間に 1500 を指定し、1.5秒後に関数 eraseText を実行する
function typeText() {
  typingText.textContent = text.slice(0, index);
  if (index < text.length) {
    index++;
    const randomInterval = Math.floor(Math.random() * 350) + 50;
    setTimeout(typeText, randomInterval);

  } else { // すべての文字が表示されたら

    // 一文字ずつ消去する関数を1.5秒後に実行する
    setTimeout(eraseText, 1500);

  }
}

以上で、一文字ずつ表示する関数 typeText を定義することができました。この関数を setTimeout() メソッドで呼び出して、1秒後に文字表示が開始されるようにしましょう。

// 一文字ずつ表示する関数を1秒待ってから実行する
setTimeout(typeText, 1000);

// 一文字ずつ表示する関数
function typeText() {
  typingText.textContent = text.slice(0, index);
  if (index < text.length) {
    index++;
    const randomInterval = Math.floor(Math.random() * 350) + 50;
    setTimeout(typeText, randomInterval);
  } else {
    setTimeout(eraseText, 1500);
  }
}

一文字ずつ消去する関数

今度は、一文字ずつ消去する関数を定義していきます。ここでは、関数名を eraseText とします。

// 一文字ずつ消去する関数
function eraseText() {
 
  // 一文字ずつ消去する処理
  // …

}

次の手順でコードを書いていきましょう。

  1. 文字を一つ消去して表示する
  2. 文字を消去するか追加するか処理を分ける
  3. 一定間隔で一文字ずつ消去する
  4. すべての文字が消去されたら文字を追加する関数へ移る

文字を一つ消去して表示する

この関数を最初に実行するときは、文字がすべて表示されている状態ですね。一文字消去してから、文字列を表示しましょう。

  • 変数 index の値を1減らす
  • 文字列の範囲を指定して表示する
function eraseText() {

  // 変数indexを1減らす(文字を一つ消去する)
  index--;
  // 最初の文字〜変数indexまでの文字列を表示する
   typingText.textContent = text.slice(0, index);

}

文字を消去するか追加するか処理を分ける

次は、 if...else 文です。変数 index の値によって、文字を消去するか追加するか、処理を分けます。

  • 変数 index0 より大きい、つまり、まだ文字列が表示されているなら一文字消去する
  • すべての文字が消去されたら、再び文字を追加する処理を行う
function eraseText() {
  index--;
  typingText.textContent = text.slice(0, index);

  // もしまだ文字列が表示されているなら
  if (index > 0) {

    // 一文字ずつ消去する処理
    // …

  } else { // すべての文字が消去されたら

    // 一文字ずつ追加する処理
    // …

  }
}

一定間隔で一文字ずつ消去する

if 文の条件が満たされている間は、一文字消去してその文字列を表示します。そのために、setTimeout() メソッドで関数 eraseText を呼び出しましょう。文字を追加するときはランダムな間隔で表示しましたが、文字の消去は一定間隔で行いますよ。

  • 遅延時間に 100 を指定し、0.1 秒待ってから関数 eraseText を実行する
function eraseText() {
  index--;
  typingText.textContent = text.slice(0, index);
  if (index > 0) {

    // 一文字ずつ消去する関数を0.1秒待ってから実行する
    setTimeout(eraseText, 100);

  } else {
    // …
  }
}

すべての文字が消去されたら文字を追加する関数へ移る

続いて、 else の部分です。 if (index > 0) の条件が満たされなくなるのは、すべての文字が消去されたときですね。文字の消去をストップして、再び文字を追加する関数をスタートしますよ。

文字の追加を始めるために、setTimeout() メソッドで関数 typeText を呼び出します。すべての文字が消去されたあとまたすぐに文字の表示を始めるのではなく、少し待ってから表示されるようにするためです。

  • 遅延時間に 1500 を指定し、1.5秒後に関数 typeText を実行する
function eraseText() {
  index--;
  typingText.textContent = text.slice(0, index);
  if (index > 0) {
    setTimeout(eraseText, 100);

  } else { // すべての文字が消去されたら

    // 一文字ずつ表示する関数を1.5秒後に実行する
    setTimeout(typeText, 1500);

  }
}

以上で、一文字ずつ消去する関数 eraseText を定義することができました。

完成コード

タイピングアニメーションのコードが完成です。

//********************************
// タイピングアニメーションのコード
//********************************

const typingText = document.querySelector('.typingText');
const text = 'Welcome to Pyxofy!';
let index = 1;

setTimeout(typeText, 1000);

// 一文字ずつ表示する関数
function typeText() {
  typingText.textContent = text.slice(0, index);
  if (index < text.length) {
    index++;
    const randomInterval = Math.floor(Math.random() * 350) + 50;
    setTimeout(typeText, randomInterval);
  } else {
    setTimeout(eraseText, 1500);
  }
}

// 一文字ずつ消去する関数
function eraseText() {
  index--;
  typingText.textContent = text.slice(0, index);
  if (index > 0) {
    setTimeout(eraseText, 100);
  } else {
    setTimeout(typeText, 1500);
  }
}

See the Pen Javascript - Typewriter Effect Animation by Pyxofy (@pyxofy) on CodePen.


まとめ

今回は、キーボードで入力しているかのようなタイピングアニメーションを JavaScript で作りました。

「文字を表示する関数」と「文字を消去する関数」を交互に呼び出すことで、文字の入力と削除の様子を表現しました。文字表示の間隔をランダムにしたので、繰り返されるたびにアニメーションのタイミングは微かに異なります。setTimeout() メソッドに指定する遅延時間を変更してみたり、お好みの文字列を用意して、タイピングアニメーションをぜひ楽しんでくださいね。

最後まで読んでいただき、ありがとうございます。この記事をシェアしてくれると嬉しいです!

SNSで Pyxofy とつながりましょう! LinkedInThreadsMastodon X (Twitter) @pyxofyFacebook

関連記事

JavaScript - 条件分岐の基本 - if 文の書き方と true, false の意味
if 文は、「もし〇〇ならAをする、そうじゃなかったらBをする」のように、条件によって処理を分岐させるための文です。if 文を理解する際に必要になる、真理値(真偽値)の true と false についても、一緒に学んでいきましょう。
CSS Art – How to Make Image Masks and Knockout Text
Ever wondered how colorful CSS gradients can be combined with mask and text. Step-by-step article to create CSS mask and knockout text.
CSS Animation – Text Background Animation
Do you love lava lamps, swirling colors, and flashy stripes? In this step-by-step article, we’ll learn how to make animated gradients in CSS.
スクラッチプログラミング - セリフを一文字ずつひょうじしよう
スプライトがいうセリフの文字を、キーボードで入力(にゅうりょく)されているかのように、ひとつずつ表示(ひょうじ)する方法(ほうほう)をしょうかいします。「ブロック定義(ていぎ)」と「変数(へんすう)」をつかってプログラミングします。