Last updated on

iPhone で `:hover` が残る理由と `:active` の使い分け

  • CSS
  • Sass
  • iPhone
  • hover
  • active

PC では自然に見える :hover の演出も、iPhone では思わぬ挙動になることがあります。
よくあるのが、タブ切り替えボタンをタップしたあとも :hover の見た目が残る というケースです。

これは CSS の書き方ミスというより、タッチ端末と :hover の相性 によるものです。ここでは、なぜ起きるのかと、どう書き分けると安定しやすいかを整理します。

:hover は本来マウス向け

:hover は、本来「ポインタが要素の上に乗っている状態」です。

a:hover {
  opacity: 0.7;
}

PC では「マウスを乗せたら反応し、離したら戻る」なので直感的です。
ただし iPhone のようなタッチ端末には、常時乗っているポインタがありません。

そのため Safari は、場面によって タップを hover の代わりのように扱う ことがあります。結果として、タップ後に :hover 相当の見た目が残ることがあります。

なぜタブボタンで起きやすいのか

タブ切り替え UI では、見た目の変化が複数あります。

  • PC でマウスを乗せたときの反応
  • タップした瞬間の反応
  • 選択中タブの見た目

この3つを全部 :hover で片付けようとすると、タッチ端末で状態が混ざりやすくなります。

特に「押したあとも :hover の見た目が残る」と、今選ばれている .is-active の見た目 と競合しやすくなります。

「タップした瞬間だけ」なら :active

タップした瞬間だけ反応して、指を離したら戻したいなら、基本は :active を使います。

.tab-button:active {
  opacity: 0.7;
}

:active は「押している間だけ」なので、タップ後に残り続けません。

ただし、これは 選択状態 を表すものではありません。
タブが選ばれたままの見た目は、.is-active のようなクラスで持つ方が安定します。

:hover は hover できる端末だけに限定する

タッチ端末で :hover を残したくないなら、いちばん安全なのは hover を hover 可能端末だけに限定すること です。

@media (any-hover: hover) {
  .tab-button:hover {
    opacity: 0.7;
  }
}

これなら、マウスのある端末では :hover が効き、タッチ中心の端末では不要な hover 演出を避けやすくなります。

実務での役割分担

タブやボタンでは、状態を次のように分けると整理しやすいです。

  • :hover PC のホバー反応

  • :active タップ / クリックの瞬間反応

  • .is-active 選択中・開いている状態

  • :focus-visible キーボード操作時の見た目

例:

.tab-button.is-active {
  background: #333;
  color: #fff;
}

@media (any-hover: hover) {
  .tab-button:hover {
    opacity: 0.7;
  }
}

.tab-button:active {
  opacity: 0.7;
}

.tab-button:focus-visible {
  outline: 2px solid #333;
  outline-offset: 2px;
}

このように分けると、PC / タッチ / キーボードの役割が重なりにくくなります。

Sass の mixin にするなら

同じパターンを繰り返すなら、Sass 側で hover 用とタッチ用を分けておくと便利です。

// iPhone などのタッチ端末では、:hover 相当の見た目がタップ後も残ることがある
@mixin hover-opacity($opacity: 0.6, $duration: 0.4s) {
  transition: opacity $duration;
  &:hover {
    opacity: $opacity;
  }
}

// ホバーのスタイルを継続させないため、any-hover: hover に限定し、タッチデバイス向けに :active を追加
@mixin tab-hover-opacity($opacity: 0.6, $duration: 0.4s) {
  transition: opacity $duration;
  @media (any-hover: hover) {
    &:hover {
      opacity: $opacity;
    }
  }

  &:active {
    opacity: $opacity;
  }
}

この考え方なら、

  • 通常リンクやPC向け演出は hover-opacity
  • タブやタッチ端末を意識するボタンは tab-hover-opacity

と使い分けやすくなります。

まとめ

iPhone で :hover がタップ後も残るのは、Safari がタップを hover 相当として扱うことがあるためです。

そのため、タブ切り替えやボタンでは次の整理が有効です。

  • :hover@media (any-hover: hover) で限定する
  • タップ瞬間だけの反応は :active
  • 選択状態は .is-active
  • キーボード操作は :focus-visible

:hover だけで全部を表現しようとせず、「マウス」「タップ」「選択状態」を分ける と、タッチ端末でも挙動が安定しやすくなります。