第2章-3節: JavaScriptでもっとすごいツールチップを!

前のページでは、HTMLとCSSだけで基本的なツールチップが作れることを見たね。シンプルで手軽だけど、もっと複雑なことをしようとすると、CSSだけではちょっと限界が見えてくるんだ。

そこで登場するのが、ウェブページに動きや対話性を加えるプログラミング言語、JavaScriptだ! JavaScriptを使うと、ツールチップはもっと賢く、もっと便利になるよ。どんなことができるようになるのか、一緒に探っていこう!

🚀 なぜJavaScriptを使うの? CSSだけじゃダメ?

CSSの:hoverで作るツールチップは手軽だけど、例えばこんなことは苦手なんだ。

  • ツールチップの内容を、マウスを乗せた要素によってガラッと変えたい(例えば、商品のIDから詳しい情報をデータベースから取ってきて表示する、みたいなこと)。
  • マウスカーソルの動きに合わせて、ツールチップがフワフワと追いかけてくるようにしたい。
  • ツールチップの表示・非表示のタイミングを細かく制御したい(例えば、少し遅れて表示させたり)。
  • スマートフォンなど、マウスホバーがないタッチデバイスでもツールチップを使いたい(例えばクリックで表示)。
  • ツールチップが画面の端からはみ出さないように、自動で位置を調整したい。

JavaScriptを使えば、これらの「もっとこうしたい!」という願いを叶えることができるんだ。プログラムで細かく動きを制御できるから、表現の幅がグンと広がるよ!

📜 JavaScriptでツールチップを作る基本的な流れ

JavaScriptでツールチップを作る基本的なステップはこんな感じだ。

  1. HTMLの準備:
    • ツールチップを表示させたい要素(トリガー要素)を用意する。これには、目印となるclass名や、ツールチップの内容を保持するためのdata-*属性を付けておくと便利だよ。
    • ツールチップ本体となる要素をHTMLにあらかじめ用意しておくか、JavaScriptで動的に作り出す。今回は、あらかじめHTMLに一つだけ用意しておく方法を見てみよう。
  2. CSSの準備:
    • ツールチップ本体の基本的な見た目(背景色、文字色、パディングなど)や、初期状態(最初は非表示にしておくなど)はCSSでスタイルを定義しておく。
  3. JavaScriptの処理:
    1. 要素の取得: トリガー要素やツールチップ本体の要素をJavaScriptで取得する。
    2. イベントリスナーの設定: トリガー要素にマウスが乗った時 (mouseover)、離れた時 (mouseout)、動いた時 (mousemove) などの「イベント」を監視する仕組み(イベントリスナー)を設定する。
    3. ツールチップの表示処理:
      • トリガー要素からツールチップに表示したい内容(例えばdata-tooltip属性の値)を取得する。
      • ツールチップ本体の要素に、その内容を書き込む。
      • ツールチップ本体の要素の位置を調整する(例えば、マウスカーソルの近く)。
      • ツールチップ本体の要素を表示状態にする(CSSのクラスを付けたり、スタイルを直接変更したり)。
    4. ツールチップの非表示処理:
      • ツールチップ本体の要素を非表示状態にする。

なんだか難しそうに聞こえるかもしれないけど、一つ一つの部品はそんなに複雑じゃないんだ。順番に見ていこう!

🛠️ 実装してみよう!JavaScriptツールチップ

ここでは、マウスを乗せるとその要素のdata-tooltip属性に書かれた内容が表示され、マウスカーソルに少し遅れてついてくるツールチップを作ってみるよ。

1. HTMLの準備

まず、ツールチップを表示するための「箱」を一つだけHTMLのどこか(通常は<body>の直下など)に用意しておく。この箱は普段は隠しておいて、JavaScriptが必要な時に表示するんだ。

<!-- ツールチップ本体 (最初は非表示) -->
<div id="js-tooltip"></div>

<!-- トリガーとなる要素の例 -->
<p>
  ここにマウスを乗せると
  <span class="tooltip-trigger-js" data-tooltip="これはJavaScriptで表示されるツールチップです!">最初のトリガー</span>
  が表示されます。もう一つ、
  <span class="tooltip-trigger-js" data-tooltip="こっちは別の内容だよ!マウスについてくる感じ!">二番目のトリガー</span>
  もあります。
</p>
<p>
  クリックで表示する例:
  <span class="tooltip-trigger-js-click" data-tooltip="クリックありがとう!もう一度クリックで消えるよ。">ここをクリック!</span>
</p>
  • <div id="js-tooltip"></div>: これがツールチップの内容を表示する専用の箱。idを付けてJavaScriptから簡単にアクセスできるようにする。
  • .tooltip-trigger-js: このクラスが付いた要素がツールチップのトリガーになる。
  • data-tooltip="...": この「データ属性」に、ツールチップとして表示したい文字列を書いておく。JavaScriptはここから内容を取り出すんだ。

2. CSSの準備

#js-tooltip の基本的なスタイルと、トリガー要素の簡単なスタイルをCSSで定義するよ。#js-tooltip は普段はdisplay: none;で見えなくしておき、position: fixed;で画面上のどこにでも表示できるようにしておくのがポイントだ。

#js-tooltip {
  position: fixed;
  background-color: #2c3e50; /* 濃い青色 */
  color: white;
  padding: 10px 15px;
  border-radius: 5px;
  font-size: 0.95em;
  z-index: 9999;         /* とても手前に表示 */
  display: none;           /* 初期状態は非表示 */
  pointer-events: none;   /* ツールチップ自体がマウスイベントを邪魔しないように */
  opacity: 0;            /* フェードイン用 */
  transition: opacity 0.2s ease-in-out;
}
.tooltip-trigger-js {
  border-bottom: 1px dashed #27ae60; /* 緑色の破線 */
  cursor: help;
}

3. JavaScriptの魔法!

いよいよJavaScriptのコードだ。ちょっと長くなるけど、何をしているかコメントで説明するね。

// DOMが読み込まれたら実行
document.addEventListener('DOMContentLoaded', () => {
  const tooltipElement = document.getElementById('js-tooltip');
  const triggers = document.querySelectorAll('.tooltip-trigger-js');
  const clickTriggers = document.querySelectorAll('.tooltip-trigger-js-click');
  let tooltipTimeout; // 遅延表示用タイマー

  // マウスホバーで表示するツールチップの設定
  triggers.forEach(trigger => {
    trigger.addEventListener('mouseover', (event) => {
      const tooltipText = event.target.dataset.tooltip;
      if (tooltipText) {
        tooltipElement.textContent = tooltipText;
        tooltipElement.style.display = 'block';
        // すぐにopacityを1にするとtransitionが効かない場合があるので少し遅らせる
        requestAnimationFrame(() => {
            tooltipElement.style.opacity = '1';
        });
        moveTooltip(event); // 初期位置設定
      }
    });

    trigger.addEventListener('mousemove', (event) => {
      moveTooltip(event);
    });

    trigger.addEventListener('mouseout', () => {
      tooltipElement.style.opacity = '0';
      // transitionの時間後にdisplay:noneにする
      setTimeout(() => {
          tooltipElement.style.display = 'none';
      }, 200); // transitionの時間と合わせる (0.2s = 200ms)
    });
  });

  // クリックで表示/非表示するツールチップの設定
  clickTriggers.forEach(trigger => {
    trigger.addEventListener('click', (event) => {
        const tooltipText = event.target.dataset.tooltip;
        if (tooltipText) {
            // 表示中で同じトリガーなら非表示に
            if (tooltipElement.style.display === 'block' && tooltipElement.textContent === tooltipText) {
                tooltipElement.style.opacity = '0';
                setTimeout(() => { tooltipElement.style.display = 'none'; }, 200);
            } else { // そうでなければ表示
                tooltipElement.textContent = tooltipText;
                tooltipElement.style.display = 'block';
                requestAnimationFrame(() => { tooltipElement.style.opacity = '1'; });
                // クリック位置の少し下に表示 (例)
                tooltipElement.style.left = event.clientX + 15 + 'px';
                tooltipElement.style.top = event.clientY + 15 + 'px';
            }
        }
    });
  });


  // ツールチップをマウスカーソルの位置に動かす関数
  function moveTooltip(event) {
    let x = event.clientX;
    let y = event.clientY;

    // ツールチップが画面の右端や下端からはみ出ないように調整
    const tooltipRect = tooltipElement.getBoundingClientRect();
    const viewportWidth = window.innerWidth;
    const viewportHeight = window.innerHeight;

    // 右端チェック
    if (x + tooltipRect.width + 15 > viewportWidth) {
      x = viewportWidth - tooltipRect.width - 15;
    } else {
      x += 15; // カーソルの少し右に
    }
    // 下端チェック
    if (y + tooltipRect.height + 15 > viewportHeight) {
      y = viewportHeight - tooltipRect.height - 15;
    } else {
      y += 15; // カーソルの少し下に
    }
    // 上端、左端にはみ出す場合の調整も加えるとより親切
    if (x < 0) x = 0;
    if (y < 0) y = 0;


    tooltipElement.style.left = x + 'px';
    tooltipElement.style.top = y + 'px';
  }
});

このコードでは、主にこんなことをしているよ。

  • DOMContentLoaded: HTMLが全部読み込まれてからJavaScriptを実行するためのおまじない。
  • document.getElementById('js-tooltip'): IDを使ってツールチップ本体の要素を取得。
  • document.querySelectorAll('.tooltip-trigger-js'): 指定したクラス名を持つ全てのトリガー要素を取得。
  • forEachループ: 各トリガー要素に対して、イベントリスナーを設定。
  • event.target.dataset.tooltip: イベントが発生した要素のdata-tooltip属性の値を取得。
  • tooltipElement.textContent = ...: ツールチップ本体にテキストを設定。
  • tooltipElement.style.display = 'block' / 'none': ツールチップの表示/非表示を切り替え。
  • tooltipElement.style.opacity = '1' / '0': フェードイン/アウト効果。
  • event.clientX, event.clientY: マウスカーソルのX座標、Y座標を取得。
  • moveTooltip関数: ツールチップの位置を調整。画面からはみ出ないような簡単なチェックも入れているよ。
  • クリックで表示するツールチップは、表示状態をトグル(切り替え)するようにしている。

デモで体験!

さあ、実際に上のHTML、CSS、JavaScriptを組み合わせるとどうなるか見てみよう!下のテキストにマウスを乗せたり、クリックしたりしてみてね。

JavaScriptの力で、この部分この部分にマウスを乗せてみよう。 ツールチップがフワッと表示されて、マウスに少しついてくるのが分かるかな?
さらに、ここをクリックするタイプのツールチップもあるよ!

(実際の動作は、このページに上記のHTML、CSS、JavaScriptが適用されていれば確認できます。)

💡 もっとできること(応用アイデア)

JavaScriptを使えば、ツールチップはもっと色々なことができるようになるよ。

  • 遅延表示: マウスを乗せてから0.5秒後に表示する、など。setTimeoutを使えば実現できる。
  • Ajaxで内容を取得: サーバーから最新の情報を取ってきてツールチップに表示する。例えば、ユーザー名にマウスを乗せたらその人のプロフィール概要を表示するなど。
  • キーボード操作対応: Tabキーでフォーカスが当たった時にもツールチップを表示できるようにする(アクセシビリティ向上のために大切!)。
  • より高度な位置調整: ツールチップが画面の端で隠れないように、自動的に上下左右の位置を賢く変える。

これらは少し高度なテクニックになるけど、基本が分かればきっと挑戦できるはずだ!

🇬🇧英語の豆知識コーナー

JavaScriptプログラミングでよく出てくる言葉だよ!

  • Event Listener

    意味:イベントリスナー(特定のイベントの発生を待ち受け、処理を実行する仕組み)

    Original: We added an event listener to the button to detect clicks.

    意訳:クリックを検知するために、ボタンにイベントリスナーを追加しました。

  • DOM Manipulation

    意味:DOM操作(Document Object Model をプログラムで変更すること)

    Original: JavaScript is often used for DOM manipulation to make web pages interactive.

    意訳:JavaScriptは、ウェブページをインタラクティブにするためのDOM操作によく使われます。

  • Dynamic Content

    意味:動的コンテンツ(状況に応じて内容が変化するコンテンツ)

    Original: The news feed displays dynamic content that updates frequently.

    意訳:ニュースフィードには、頻繁に更新される動的コンテンツが表示されます。

  • Asynchronous (Ajax)

    意味:非同期の(処理の完了を待たずに次の処理に進むこと。AjaxはAsynchronous JavaScript and XMLの略)

    Original: Ajax allows web pages to update content asynchronously without reloading the entire page.

    意訳:Ajaxを使うと、ウェブページ全体を再読み込みすることなく、非同期にコンテンツを更新できます。

まとめ

今回は、JavaScriptを使ってツールチップを作る方法の基本を見てきたね。

  • JavaScriptを使うと、CSSだけでは難しかった高度な制御や動的な内容の表示が可能になる。
  • イベントリスナーでマウスの動きを捉え、DOM操作でツールチップの表示や内容をコントロールする。
  • data-*属性を使えば、HTML側にツールチップの内容を持たせやすい。

JavaScriptのコードは少し複雑に見えるかもしれないけど、一つ一つの命令を追っていけば、何をしているかきっと理解できるはずだよ。実際にコードを書いて動かしてみるのが一番の近道だ!

ツールチップ一つとっても、色々な作り方や工夫の仕方があるんだね。次のページでは、ツールチップを作る上でとても大切な「アクセシビリティ」について考えてみよう。