Tooltip — ホバーで補足情報を表示する

通知・オーバーレイ 初級

このコンポーネントについて

ツールチップ(tooltip)は要素にホバーしたとき、補足情報を小さなボックスで表示するUIパターンです。アイコンボタンの意味を説明したり、省略テキストの全文を見せたりと、画面をすっきり保ちながら情報を補完したい場面で活躍します。

このページでは実装方法の違いで2パターンを紹介します。パターン1はJavaScript不要・CSSの疑似要素だけで作る方法、パターン2はJSを使ってテキストが省略(...)されているときだけ自動でツールチップを出す実用的な方法です。

  • パターン1:CSSのみdata-tooltip 属性と ::before / ::after 疑似要素だけで実装。JSゼロで動く
  • パターン2:JS版 — テキストの省略(text-overflow: ellipsis)が発生している要素だけにツールチップを表示。データが動的でも対応できる
  • 矢印ポインター付き — 両パターンともツールチップ下部に三角矢印を表示し、どの要素への説明か分かりやすくする

実装のポイント・注意点

パターン1でよく詰まるのが position: relative の書き忘れです。::before / ::after 疑似要素は position: absolute で配置されますが、ボタン自身に position: relative がないとページ全体が基点になり、ツールチップが画面の左上に飛んでしまいます。ボタン側に position: relative を忘れずに指定しましょう。

CSS の三角矢印は border トリックで作ります。実体のないボックスの上辺だけ色をつけ、左右を透明にすると三角形に見えます。「なぜこれで三角になるのか」は最初は不思議に感じますが、サンプルCSSのコメントを読むと仕組みが分かります。

パターン2は el.scrollWidth > el.clientWidth で省略が発生しているかを検出します。省略されていない行ではツールチップが出ないため、短い文字列のデータが混在してもそのまま使えます。ツールチップ要素は document.body に追加して position: fixed で配置するのがポイントで、overflow: hidden な親要素の中に入れるとクリッピングされて見えなくなるのを防いでいます。

HTML・CSS・バニラJavaScriptのみで実装しており、フレームワーク不要でコピペすぐに動きます。

デモ

Pattern 1 — CSSのみ

Pattern 2 — JS版(省略テキスト補完)

省略(...)されている行にホバーすると全文が表示されます。

    サンプルソース

    3つのファイルを同じフォルダに保存し、index.html をブラウザで開くとすぐに動作確認できます。
    ファイル名:index.html / style.css / script.js — 保存時の文字コードは UTF-8 を指定してください(Shift-JISだと日本語が文字化けします)。

    <!DOCTYPE html>
    <html lang="ja">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <title>ツールチップ サンプル</title>
      <link rel="stylesheet" href="./style.css">
    </head>
    <body>
    
    <!-- ===== Pattern 1: CSSのみ ===== -->
    <p class="section-label">Pattern 1 — CSSのみ</p>
    <div class="tp-buttons">
      <!-- data-tooltip="〇〇" に書いた文字がそのままツールチップに表示される -->
      <button class="tp-btn" data-tooltip="削除" type="button">🗑</button>
      <button class="tp-btn" data-tooltip="編集" type="button">✏️</button>
      <button class="tp-btn" data-tooltip="シェア" type="button">🔗</button>
      <button class="tp-btn" data-tooltip="お気に入り" type="button">⭐</button>
    </div>
    
    <!-- ===== Pattern 2: JS版(テキスト省略補完) ===== -->
    <p class="section-label" style="margin-top: 32px;">Pattern 2 — JS版(省略テキスト補完)</p>
    <p class="list-desc">省略(...)されている行にホバーすると全文が表示されます。</p>
    <ul class="tp-list" id="tp-list"></ul>
    
    <script src="./script.js"></script>
    </body>
    </html>
    *, *::before, *::after { box-sizing: border-box; }
    
    body {
      font-family: sans-serif;
      padding: 32px;
      color: #1A2332;
      background: #F8FAFC;
    }
    
    .section-label {
      font-size: 12px;
      font-weight: 700;
      color: #2B7FE8;
      margin: 0 0 12px;
      letter-spacing: 0.04em;
    }
    
    /* =============================================
       Pattern 1: CSSのみ — アイコンボタン用ツールチップ
       ============================================= */
    
    .tp-buttons {
      display: flex;
      gap: 12px;
    }
    
    .tp-btn {
      /* ★ポイント1: position: relative が必須
         ::before / ::after は position: absolute で配置される。
         このボタン自身に relative がないとページ全体が基点になり、左上に飛んでしまう。 */
      position: relative;
      width: 44px;
      height: 44px;
      font-size: 18px;
      background: #fff;
      border: 1.5px solid #D0D7E0;
      border-radius: 10px;
      cursor: pointer;
      transition: background 0.15s, border-color 0.15s;
      font-family: sans-serif;
    }
    
    .tp-btn:hover {
      background: #F0F4FF;
      border-color: #2B7FE8;
    }
    
    /* ★ポイント2: ::before でツールチップ本体を作る
       content: attr(data-tooltip) で HTML 属性の値を表示できる。
       bottom: calc(100% + 8px) でボタンの真上 8px に配置。
       left: 50% + transform でボタン中央に揃える。 */
    .tp-btn::before {
      content: attr(data-tooltip);
      position: absolute;
      bottom: calc(100% + 8px);
      left: 50%;
      transform: translateX(-50%);
      white-space: nowrap;
      background: #1A2332;
      color: #fff;
      font-size: 12px;
      padding: 5px 10px;
      border-radius: 6px;
      pointer-events: none;
      /* 初期状態は非表示 */
      opacity: 0;
      visibility: hidden;
      transition: opacity 0.15s, visibility 0.15s;
    }
    
    /* ★ポイント3: ::after でツールチップ下部の三角矢印を作る
       border トリックの仕組み:実体のない 5px のボックスを作り
       上辺だけ色をつけて左右を透明にすると下向き三角に見える。 */
    .tp-btn::after {
      content: '';
      position: absolute;
      bottom: calc(100% + 3px);
      left: 50%;
      transform: translateX(-50%);
      border: 5px solid transparent;
      border-top-color: #1A2332;
      pointer-events: none;
      /* 初期状態は非表示 */
      opacity: 0;
      visibility: hidden;
      transition: opacity 0.15s, visibility 0.15s;
    }
    
    /* ★ポイント4: ホバー時に表示
       visibility も使う理由:opacity: 0 だけだと要素が残り
       pointer-events が生きたままになるため、visibility: hidden も併用する。 */
    .tp-btn:hover::before,
    .tp-btn:hover::after {
      opacity: 1;
      visibility: visible;
    }
    
    /* =============================================
       Pattern 2: JS版 — テキスト省略補完
       ============================================= */
    
    .list-desc {
      font-size: 13px;
      color: #5A6A7A;
      margin: 0 0 10px;
    }
    
    .tp-list {
      list-style: none;
      margin: 0;
      padding: 0;
      width: 280px;
      border: 1.5px solid #D0D7E0;
      border-radius: 10px;
      overflow: hidden;
      background: #fff;
    }
    
    .tp-list-item {
      padding: 10px 14px;
      font-size: 14px;
      color: #1A2332;
      border-bottom: 1px solid #EEF1F5;
      /* ★ここで省略表示を設定 */
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      cursor: default;
    }
    
    .tp-list-item:last-child {
      border-bottom: none;
    }
    
    /* 省略が発生している行にホバーしたとき */
    .tp-list-item.is-truncated:hover {
      background: #F8FAFC;
    }
    
    /* =============================================
       JS が動的に生成するツールチップボックス
       ============================================= */
    .tp-tooltip-box {
      position: fixed;
      background: #1A2332;
      color: #fff;
      font-size: 12px;
      font-family: sans-serif;
      padding: 6px 12px;
      border-radius: 6px;
      pointer-events: none;
      white-space: nowrap;
      z-index: 9999;
      /* 下向き三角矢印 */
      transform: translateX(-50%) translateY(calc(-100% - 8px));
    }
    
    .tp-tooltip-box::after {
      content: '';
      position: absolute;
      top: 100%;
      left: 50%;
      transform: translateX(-50%);
      border: 5px solid transparent;
      border-top-color: #1A2332;
    }
    // パターン2:テキスト省略が発生している行にツールチップを表示
    
    var items = [
      'ワイヤレスノイズキャンセリングヘッドフォン Pro Max 2024年モデル',
      'スマートウォッチ S7',
      'USB-C 7-in-1 マルチポートハブ(4K HDMI・SDカード対応)',
      'スマートスピーカー Hub Mini',
      'Bluetoothキーボード 折りたたみ式コンパクト JIS配列 バックライト付き',
      'モバイルバッテリー 20000mAh PD 65W 急速充電対応',
    ];
    
    // リスト行を生成して追加
    var list = document.getElementById('tp-list');
    items.forEach(function(text) {
      var li = document.createElement('li');
      li.className = 'tp-list-item';
      li.textContent = text;
      list.appendChild(li);
    });
    
    // 各行にホバーイベントを設定
    var listItems = document.querySelectorAll('.tp-list-item');
    var tooltip = null;
    
    listItems.forEach(function(el) {
      el.addEventListener('mouseenter', function() {
        // scrollWidth > clientWidth のときだけ省略が発生している
        if (el.scrollWidth <= el.clientWidth) return;
    
        el.classList.add('is-truncated');
    
        // ツールチップ要素を生成
        tooltip = document.createElement('div');
        tooltip.className = 'tp-tooltip-box';
        tooltip.textContent = el.textContent; // XSS対策:textContent を使う
    
        document.body.appendChild(tooltip);
    
        // 要素の位置を取得してツールチップを重ねる
        var rect = el.getBoundingClientRect();
        tooltip.style.left = (rect.left + rect.width / 2) + 'px';
        tooltip.style.top  = rect.top + 'px';
      });
    
      el.addEventListener('mouseleave', function() {
        el.classList.remove('is-truncated');
        if (tooltip) {
          tooltip.remove();
          tooltip = null;
        }
      });
    });

    AI用プロンプト

    各パターンのプロンプトをコピーしてAIに渡すと、同様のコンポーネントを生成できます。

    ChatGPTやClaudeにこのプロンプトを渡すと、同様のコンポーネントをゼロから生成・カスタマイズできます。ライブラリ指定や表示方向の変更など、要件を追記して使うのがおすすめです。

    ※ このプロンプトを使ってもデモとまったく同じ動作にならない場合があります。AIの解釈や生成タイミングによって差が出ることをご了承ください。

    💡 jQuery・Vue・React など特定のライブラリで実装したい場合は、プロンプトの末尾に「〇〇を使って実装してください」と追記してください。

    Pattern 1 — CSSのみ

    # ツールチップ(CSSのみ版)作成依頼
    
    ## 概要
    JavaScriptを使わず、CSSの疑似要素だけでツールチップを実装してください。
    アイコンボタンにホバーすると、ボタンの上部にラベルが表示されます。
    
    ## 要件
    - ツールチップのテキストは HTML の `data-tooltip` 属性で指定できるようにする
    - ツールチップはホバー時にボタン真上に表示し、下向き三角矢印をつける
    - `::before` でツールチップボックス、`::after` で三角矢印を作る
    - ホバー前は非表示(opacity: 0 / visibility: hidden)、ホバー時に表示(opacity: 1)
    - transition でフェードイン・アウトする
    - サンプルとしてアイコンボタンを4つ横並びに配置する(例:削除・編集・シェア・お気に入り)
    
    ## 技術仕様
    - HTML / CSS のみで実装(JavaScriptは使用しない)
    - 外部ライブラリ:なし
    - レスポンシブ対応:不要
    
    ## 動作詳細
    各ボタンに `data-tooltip="削除"` のように属性を書くだけでツールチップが表示される。
    `position: relative` を持つ親要素に対して `::before` / `::after` が `position: absolute` で配置される仕組みをコメントで説明してください。
    ツールチップは要素の `bottom: calc(100% + 8px)` に配置し、`left: 50%; transform: translateX(-50%)` で水平中央に揃えます。
    
    ## 出力形式
    HTML・CSS・JavaScriptを分けて出力してください。
    各ファイルは単独でコピー&ペーストして使えるよう記述してください。

    Pattern 2 — JS版(省略テキスト補完)

    # ツールチップ(テキスト省略補完・JS版)作成依頼
    
    ## 概要
    テキストが省略(...)表示されている要素にのみ、ホバーで全文を表示するツールチップを実装してください。
    省略されていない行ではツールチップは出ません。
    
    ## 要件
    - リスト行を固定幅コンテナに入れ、`text-overflow: ellipsis` で省略表示する
    - `mouseenter` イベントで `scrollWidth > clientWidth` を確認し、省略が発生しているときだけツールチップを表示する
    - ツールチップ要素は JavaScript で動的生成し、`document.body` に追加する
    - ツールチップの位置は `getBoundingClientRect()` + `position: fixed` で対象行の上部に表示する
    - `mouseleave` でツールチップ要素を `remove()` して削除する
    - ツールチップのテキストは `textContent` で設定する(innerHTML 禁止)
    
    ## 技術仕様
    - HTML / CSS / バニラJavaScript で実装
    - 外部ライブラリ:なし
    - レスポンシブ対応:不要
    
    ## 動作詳細
    商品名などの長いテキストを `max-width` で固定した `<li>` に表示し、省略が起きている行のみホバーでフルテキストを表示する。
    省略が起きていない行(短い商品名など)ではツールチップを出さない挙動を必ず実装すること。
    データは JS 配列で定義し、`createElement` + `textContent` でリスト行を動的生成してください。
    
    ## 出力形式
    HTML・CSS・JavaScriptを分けて出力してください。
    各ファイルは単独でコピー&ペーストして使えるよう記述してください。