【UX向上】@media (any-hover: hover) を使って、PCでのみホバーエフェクトを効かせる方法

Webサイトのボタンやリンクに :hover でアニメーションや色の変化をつけるのは定番の手法です。 しかし、スマートフォンやタブレットなどの「タッチデバイス」でこのボタンをタップすると、指を離した後もホバー状態のスタイルが維持されてしまう「ホバー残り(タップ残り)」という現象が起きてしまいます。

これを防ぐために使われているのが、@media (any-hover: hover) というモダンなCSSのメディアクエリです。 これを使うことで「マウスなどのホバー可能なポインティングデバイスを持っている端末」にだけ、ホバー時のスタイルを適用することができます。

今回は、この便利なメディアクエリをSCSSの @mixin として定義し、効率よく使い回すためのテクニックと、従来の :hover との挙動の違いをご紹介します!

デモ動作

See the Pen @media (any-hover: hover) by mikanbako (@mikanbako) on CodePen.

全画面でのデモ動作は以下のリンクからご確認下さい!(別タブで開かれます)

実装コードの紹介

【HTML】

<div class="l-wrap">
  <div class="p-buttons">
    <div class="p-buttons__item">
      <p>❌ 従来のホバー(スマホでタップ残りが起きる)</p>
      <a href="#" class="p-btn p-btn--normal">Normal Hover</a>
    </div>

    <div class="p-buttons__item">
      <p>✨ モダンなホバー(スマホではホバー処理が無視される)</p>
      <a href="#" class="p-btn p-btn--modern">Modern Hover</a>
    </div>
  </div>
</div>

【SCSS】

/* =========================================
   ① hover用のmixin定義(_mixins.scss などに記述)
========================================= */
@mixin hover {
  // ホバー機能を持つデバイス(PCなど)でのみスタイルを適用するメディアクエリ
  @media (any-hover: hover) {
    &:hover {
      @content;
    }
  }
}

.l-wrap {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

/* =========================================
   ② ボタンの共通スタイル
========================================= */
.p-buttons {
  display: flex;
  flex-direction: column;
  gap: 40px;
  
  &__item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 16px;
    font-weight: bold;
    color: #3e3e3e;
  }
}

.p-btn {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  width: 200px;
  padding: 16px;
  font-size: 18px;
  font-weight: bold;
  text-decoration: none;
  background-color: #fff;
  border-radius: 8px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  transition: all 0.3s ease;
}

/* =========================================
   ③ ホバー処理の適用(デモの比較部分)
========================================= */

/* ❌ 従来の :hover(スマホだとタップ後に色が残ってしまう) */
.p-btn--normal {
  border: 2px solid #c72c4c;
  color: #c72c4c;

  &:hover {
    background-color: #c72c4c;
    color: #fff;
  }
}

/* ✨ モダンな mixin を使ったホバー(PCでのみホバーが効く) */
.p-btn--modern {
  border: 2px solid #1bb4d4;
  color: #1bb4d4;

  // ここで作成したmixinを呼び出す
  @include hover {
    background-color: #1bb4d4;
    color: #fff;
  }
}

コードの解説・こだわったポイント

@media (any-hover: hover) とは?

これはCSSのメディアクエリの一種で、「ユーザーの主要な入力システム(マウスなど)が、要素の上にカーソルを浮かせる(ホバーする)ことができるか」を判定してくれます。

従来の :hover 擬似クラスだけを指定すると、スマートフォンなどのタッチデバイスでは、要素をタップした瞬間にホバー状態となり、別の場所をタップするまでそのスタイルが解除されないという問題がありました。 このメディアクエリで囲むことで、「マウス操作ができるPC環境でのみ、ホバーエフェクトを有効にする」という制御が可能になります。

なぜSCSSで @mixin にするのか?

ホバー処理は、ボタン・リンク・カードなど、書く場面が数え切れないほど登場します。 その度に毎回 @media (any-hover: hover) { &:hover { ... } } と記述するのは非常に冗長で、コードの可読性も下がってしまいます。

// mixinを使わない場合
.button {
  @media (any-hover: hover) {
    &:hover {
      opacity: 0.7;
    }
  }
}

// mixinを使った場合(圧倒的にスッキリ!)
.button {
  @include hover {
    opacity: 0.7;
  }
}

このように @mixin hover として定義しておくことで、たった数文字でモダンなホバー処理を呼び出せるようになり、開発スピードと保守性が向上します!

補足:ブラウザの対応状況について

今回紹介した @media (any-hover: hover) はモダンなCSSの機能ですが、現在では主要なモダンブラウザ(Chrome, Safari, Edge, Firefoxなど)およびiOS/Androidの各ブラウザでしっかりとサポートされており、問題なく安心して使用することができます。

より詳しい仕様や最新の対応状況については、以下の公式ドキュメント等をご参照ください。

・MDN: @media (any-hover)
・Can I use: any-hover

まとめ

今回は、タッチデバイスでの「ホバー残り」を防ぐモダンな実装と、それをSCSSで効率よく使い回すための @mixin 化について解説しました。

Webサイトを閲覧するユーザーの半数以上がスマートフォンを利用している現代において、タッチデバイスでのUX(ユーザー体験)を損なわない実装は、フロントエンドエンジニアにとって必須のスキルです。

今後もこのような「コードをスッキリさせる工夫(mixin化)」と「ユーザーに優しいUI設計」の両方を意識して、質の高いコーディングを心掛けていきたいと思います!

Prev
Next