UI/UX
投稿日:

比較表で”違い”にだけ動きを ─ 差分セルの一時ハイライト

比較表で違いにだけ動きを ─ 差分セルの一時ハイライト

こんにちは、WebディレクターのBigViです。最近、夫ともつ鍋を食べに行きました。東京のもつ鍋屋さん、おいしいところが多いです。元気が出ます。。

先日、クライアントから「料金プランの比較表があるけど、どこが違うのかわかりにくい」と相談されました。プランが3つあって、できることが微妙に違います。でも表が大きくて、全部同じに見えます。「違い」を探すのが大変です。

私もよくあります。比較表を見て「で、どこが違うの?」ってなります。全部のセルを1個ずつ見るのは面倒です。

そこで私が提案したのが「差分ハイライト」です。表が画面に入った瞬間、違いがあるセルだけを一瞬だけ黄色くします。300msで元の白に戻ります。ずっと黄色いわけじゃないです。「ここが違いますよ」と1回だけ教える感じ。

常にハイライトしない理由

「ずっと黄色にしておけばいいのでは?」と思うかもしれません。でも、常時ハイライトは問題があります。

まず、色が多くなります。表全体がカラフルになると、逆に見にくいです。どこが大事かわからなくなります。

それと、ユーザーは「変化」に気づきます。ずっと色がついていると、それが「普通」になります。でも、さっきまで白だったセルが一瞬だけ黄色くなると、「あ、ここが違うんだ」と気づきます。動きや色の突然の変化は、人の注意を自動的に引きます。一瞬だけ変えるから気づいてもらえるんです。

ある案件で最初、ずっと黄色にしていました。クライアントに見せたら「うーん、なんか表がうるさい」と言われました。。一時ハイライトに変えたら「これはいい感じ」と言ってくれました。

HTML構造

HTMLです。普通の比較表に、data-diff="true"をつけるだけです。

<figure class="comparison-table-wrap">
  <table class="comparison-table" id="comparisonTable">
    <thead>
      <tr>
        <th></th>
        <th>ライト</th>
        <th>スタンダード</th>
        <th>プレミアム</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>月額料金</td>
        <td data-diff="true">980円</td>
        <td data-diff="true">2,480円</td>
        <td data-diff="true">4,980円</td>
      </tr>
      <tr>
        <td>ページ数</td>
        <td>5ページ</td>
        <td data-diff="true">20ページ</td>
        <td data-diff="true">無制限</td>
      </tr>
      <tr>
        <td>SSL対応</td>
        <td>○</td>
        <td>○</td>
        <td>○</td>
      </tr>
      <tr>
        <td>独自ドメイン</td>
        <td data-diff="true">×</td>
        <td data-diff="true">○</td>
        <td data-diff="true">○</td>
      </tr>
      <tr>
        <td>サポート</td>
        <td data-diff="true">メールのみ</td>
        <td data-diff="true">メール+チャット</td>
        <td data-diff="true">電話+専任担当</td>
      </tr>
    </tbody>
  </table>
</figure>

data-diff="true"は「この行はプランごとに違う」という意味です。SSL対応みたいに全部同じ行には付けません。付けるかどうかは、HTMLを書く人が決めます。自動判定じゃないです。自動にすると、値が微妙に違うだけの行まで光ってしまいます。人が「ここは違いが大事」と判断して付けるほうがいいです。

CSSスタイル

ハイライトのアニメーションを作ります。

/* 比較表の基本スタイル */
.comparison-table-wrap {
  max-width: 720px;
  margin: 32px auto;
  overflow-x: auto;
}

.comparison-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}

.comparison-table th,
.comparison-table td {
  padding: 12px 16px;
  border: 1px solid #e5e7eb;
  text-align: center;
}

.comparison-table thead th {
  background: #f9fafb;
  font-weight: 600;
  color: #111827;
}

.comparison-table tbody td:first-child {
  text-align: left;
  font-weight: 500;
  color: #374151;
  background: #f9fafb;
}

/* 差分ハイライト */
@keyframes diff-flash {
  0% {
    background-color: #fef9c3;
  }
  100% {
    background-color: #fff;
  }
}

td[data-diff="true"].is-highlighted {
  animation: diff-flash 300ms ease-out forwards;
}

/* アニメーション苦手な人への配慮 */
@media (prefers-reduced-motion: reduce) {
  td[data-diff="true"].is-highlighted {
    animation: none;
    border-bottom: 2px solid #ca8a04;
  }
}

diff-flashがアニメーションです。薄い黄色(#fef9c3)から白に300msで戻ります。一瞬です。パッと光って、すぐ消えます。

prefers-reduced-motionも入れています。アニメーションが苦手な人は、色の変化ではなく下線で差分を示します。動きがないけど、ちゃんとわかります。私、これ毎回入れています。

JavaScriptの実装

やることは2つだけです。

  • 表が画面に入ったかを監視する
  • 入ったら、data-diff="true"のセルにクラスを1回だけ付ける
document.addEventListener('DOMContentLoaded', function() {
  var table = document.getElementById('comparisonTable');
  if (!table) return;

  var observer = new IntersectionObserver(function(entries) {
    entries.forEach(function(entry) {
      if (entry.isIntersecting) {
        highlightDiffs(table);
        observer.unobserve(table);
      }
    });
  }, {
    threshold: 0.3
  });

  observer.observe(table);
});

function highlightDiffs(table) {
  var diffCells = table.querySelectorAll('td[data-diff="true"]');
  
  diffCells.forEach(function(cell, index) {
    // 少しずつずらして光らせる
    setTimeout(function() {
      cell.classList.add('is-highlighted');
    }, index * 40);
  });
}

コード、20行ぐらいです。短いです。

ポイントはsetTimeoutindex * 40です。全部のセルが同時に光ると、一瞬すぎて気づきません。40msずつずらすことで、上から下に波のように光ります。これがいい感じです。

threshold: 0.3にしています。表の30%が見えたら発火します。表の上端がちょっと見えたぐらいでは光りません。ちゃんと表が見えてから光ります。

失敗した話

実は、私がやってしまった失敗があります。

全部のセルを光らせた

最初、全部のセルにdata-diffをつけてしまいました。SSL対応みたいに全プラン同じ行も光りました。リーダーに「全部光ったら意味ないよ」と言われました。。そうです。「違い」だけ光るから意味があるんです。

ずらし時間が長すぎた

最初、index * 200にしていました。1セルごとに200msずつ遅れます。セルが15個あると、全部光り終わるのに3秒かかりました。遅すぎます。「壊れてるのかな?」とクライアントに心配されました。40msだとスッと流れる感じになります。

スマホで表が横スクロール

スマホだと表が画面に収まりません。横スクロールになります。でもIntersectionObserverは表全体を監視しているので、画面に入ったら光ります。右側の見えていないセルも光ります。

これは仕方ないかなと思いました。ユーザーが横スクロールしたとき、もう光り終わっています。でもdata-diffのセルはbackground-color: #fffに戻っているだけなので、邪魔にはなりません。気になる場合はもう少し複雑なJSが必要ですが、私はシンプルなほうが好きです。

実際の効果

クライアントのサービスサイトに入れました。3プランの比較表がある料金ページです。

2週間後にA/Bテストの結果が出ました。Microsoft Clarityのヒートマップと、GA4のカスタムイベントで計測しています。

指標入れる前入れたあと
表の滞在時間8秒14秒
CTAクリック率3.1%4.4%(約42%増)
離脱率変化なし変化なし

表の滞在時間が伸びたのがうれしかったです。ちゃんと比較してくれているということです。前は「よくわからない」→離脱だった人が、「ここが違うのか」→CTAを押す、に変わりました。

クライアントも「これなら違いが伝わります」と喜んでくれました。

ハイライト部分のCSS + JavaScript合わせて30行ぐらいです。既存の表にdata-diffを追加するだけなので、HTMLの変更も少ないです。

Webディレクターへの補足

この実装をエンジニアに依頼するとき、伝えるポイントは3つです。

  • どの行が「差分」かを決めるのはディレクターの仕事です。全プラン同じ行は光らせない
  • ハイライトの色はブランドカラーに合わせてください。黄色が合わない場合は、薄いブランドカラーを使います
  • アニメーション時間は300ms以内にしてください。長いと「壊れた?」と思われます

あと、表がスマホで横スクロールになるサイトは、レスポンシブの確認をお願いしてください。

まとめ

今回は、比較表で「違いがあるセルだけ」を一瞬ハイライトする方法を書きました。IntersectionObserverで表が画面に入ったら、data-diffのセルだけ薄黄色→白にフラッシュさせます。

ポイントは3つです。

  • data-diff="true"で、違いがあるセルだけを指定する。全部光らせない
  • ハイライトは300ms。一瞬だけ見せてすぐ消す。ずっと色をつけない
  • セルごとに40msずつずらすと、波のように自然に見える

私のプロジェクトでは、CTAクリック率が約42%上がってくれました。実装コストは30行ぐらいで、今ある比較表にすぐ追加できます。比較表がうまく使われていないと感じるときは、試してみてください。

株式会社ファストコーディングでは、こうした比較表のUI改善やフロントエンドの実装サポートをしています。「料金ページのCVRを上げたい」「比較表をもっとわかりやすくしたい」という方は、こちらのお問い合わせフォームから気軽にご連絡ください。


※本記事は弊社外国人スタッフによる投稿です。言い回しや表現が不十分な個所がありますことご容赦いただきますようお願いいたします。
株式会社ファストコーディング