ホバーエフェクトはCSS?JS?実装パターン別の選択基準|現場で使える実践テクニック

ホバーエフェクトはCSS?JS?実装パターン別の選択基準|現場で使える実践テクニック
C
クリオ
Web制作ディレクター / フロントエンジニア

こんにちは!
今日は「ホバーエフェクトはCSS?JS?実装パターン別の選択基準」について解説します。

ホバーエフェクトで迷う現場あるある

ボタンにホバーをかけるとき、皆さんはどうしていますか?
実はね、僕も駆け出しの頃「ホバーするたびにJavaScriptを呼び出してる」という、ほんまにもったいない実装してました。
後輩から「あ、クリオさん、これCSS で書けますよ」と言われたときの恥ずかしさ、今でも覚えてます(笑)

現場でよく見るのは、ディレクターやデザイナーから「ホバーで色が変わる」「スケールアップする」みたいな要件をもらうんですけど、その瞬間に「これはJSが必要かな?」と条件反射で考えてしまう人が多いんです。
でも実際のところ、85パーセント以上のホバーエフェクトはCSSだけで十分やん。

だからこそ、判断基準をはっきり持つことが大事です。
今日はそのポイントを、実例を交えて説明していきますね。

シンプルなホバーはCSS一択です

まず確認しておきたいのが、CSSホバーの強力さです。
次のようなエフェクトなら、めっちゃCSSで対応できます。

  • 背景色の変更
  • 文字色の変更
  • ボーダーの変更
  • スケール・回転・スキュー
  • オパシティ(透明度)の変更
  • シャドウの付与
  • 複合的なトランジション

これらはすべて:hover疑似クラスとtransitionプロパティでカバーできるんです。
例えば、ボタンがホバーされたときにスケールアップと背景色が同時に変わる場合:

.button {
  background-color: #3b79b7;
  padding: 12px 24px;
  transform: scale(1);
  transition: all 0.3s ease;
}

.button:hover {
  background-color: #5a9fd4;
  transform: scale(1.1);
}

ほら、これだけです。
JavaScriptなんて一行も必要ないですよね。

僕の経験上、「ホバーでアニメーション」=「JSが必要」だと思い込んでいる人がめっちゃ多いんです。
でもtransitionがあるおかげで、CSSだけで十分スムーズなアニメーションが作れるんですよ。
しかも、パフォーマンスもいいし、コードも簡潔。
これは選ばない理由がないですよね。

注意点として、タッチデバイスでは:hoverが効かないことを頭に入れておいてください。
モバイルではホバーって概念がないので、ユーザーはタップで操作します。
そういう時は後で説明する@media (hover: hover)という書き方で、デバイスを判定できますよ。

複数の要素を連動させるならJavaScriptの出番

ここからが、CSSだけじゃ難しい領域です。

例えば、「親要素のボタンをホバーされたら、その下にある複数の子要素が順番にフェードインする」みたいなケースですね。
もしくは「ホバーされたら、全く別の場所にある要素が同時に動く」とか。

CSSの:hoverは、ホバーされた要素とその子孫にしか影響を与えられません。
兄弟要素や遠くの要素を動かしたい時点で、もうCSSだけじゃ足りないんです。

// ホバーで複数要素を制御したい場合
const button = document.querySelector('.menu-trigger');
const items = document.querySelectorAll('.menu-item');

button.addEventListener('mouseenter', () => {
  items.forEach((item, index) => {
    item.style.animationDelay = ${index * 0.1}s;
    item.classList.add('is-active');
  });
});

このように、複数要素の連動制御が必要な時は、JavaScriptの出番です。
クラスの付け外しで状態を管理して、CSSでそのクラスに対するスタイルを書く、というハイブリッドなやり方がおすすめです。

僕も現場で「ホバーされたら全要素が一斉に動く」みたいな要件をもらったことがあるんですけど、そういう時はクラスベースの設計にしておくと、後々の修正も楽ですよ。
マークアップも読みやすくなりますし。

デバイス判定が必要な時の選択肢

さっき少し触れましたけど、タッチデバイスの話をもっと深堀りしておきたいんです。

ホバーエフェクトを実装するときに忘れちゃいけないのが「このサイト、スマホでも見られるんだな」ってことです。
スマホ時代に:hoverだけで設計すると、タップしても何も反応がなく、ユーザーは「ボタン壊れてるのか?」って思っちゃいます。

そこで活躍するのが、メディアクエリの@media (hover: hover)という書き方です。

/* ホバーをサポートしてるデバイスのみ */
@media (hover: hover) {
  .button:hover {
    background-color: #5a9fd4;
    transform: scale(1.1);
  }
}

/* タッチデバイスの場合、フォーカスで反応させる */
@media (hover: none) {
  .button:active, .button:focus {
    background-color: #5a9fd4;
    transform: scale(1.1);