メディア特性を使ってデバイスに併せてhoverのスタイルを出し分ける方法

## はじめに

Qiita株式会社 アドベントカレンダー19日目は、デザインチームの@gillyが担当します！
よろしくお願いします!

https://qiita.com/advent-calendar/2021/qiita


[13日目](https://qiita.com/gilly/items/cd70d70b279334560f8b)にも記事を投稿していますので、よかったらご覧ください :pray: 
今回はメディア特性を使った `hover` のスタイルについてご紹介します。

## `:hover` で指定するとタップ後もhoverの効果が残っている

マウスをリンクにホバーしたときに、色が変わるUIはよくあると思います。

例えばscssで書くとこんなコードです。
リンクが青い文字になっていて、ホバー中は濃い青色にします。

```scss
a {
  color: #327caf;
    &:hover {
      color: #205875;
  }
}
```

実はこのコードをスマートフォンなどのタッチデバイスで実行すると、タップした後**違う要素がタップされるまでスタイルが反映**されています。
テキストリンクの色ぐらいなら…という場合もあるかもしれませんが、`:hover`をつかったドロップダウンや、タッチデバイスのタップ範囲の確保など、あなたが意図したUIで無いかもしれません。

ちなみにリンクの場合は、 `:active` があります。
`:active` の場合はタップしている間だけスタイルが反映されます。

### スマホでの挙動

| 疑似クラス | 挙動 |
|-|-|
| `:hover` | タップした後、違う要素がタップされるまでスタイルが反映 |
| `:active` | タップ中のみスタイルが反映 |

## 【解決方法】メディア特性で対象の入力デバイスを判定する

`@media screen and (min-width:480px)` などのviewportで対応する方法を紹介している記事もありますが、この方法ですとタブレットと小さなディスプレイサイズのデスクトップでは見分けがつかない場合があります。

今回は入力デバイスを判定するメディア特性を使う方法を紹介します。

:::note warn
IEは非対応です。IEのサポートは2022年には終了が予告されているため、今回対応は記載しません。
:::

### 【その１】`@media (hover: 値)` 

ホバーが利用できるデバイスか判定するメディア特性です。

メディアクエリ|判定
---|---
`@media (hover: hover)`|デスクトップなど、入力デバイスがホバーに対応している場合
`@media (hover: none)`|スマートフォンなど、ホバーに対応している入力デバイスが無い場合


### 【その2】`@media (pointer: 値)`

ポインターの精度によって判定するメディア特性です。

メディアクエリ|判定
---|---
`@media (pointer: fine)`|マウスのような正確なポインターがあるデバイスの場合
`@media (pointer: coarse)`|タッチスクリーンのようなポインターが粗いデバイスの場合
`@media (pointer: none)` | 上記のいずれでもない場合

### 【その3】`@media (any-hover: 値)` 

複数の入力デバイスがある場合、いずれかがホバーが利用できるデバイスが判定するメディア特性です。

メディアクエリ|判定
---|---
`@media (any-hover: hover)`|入力デバイスのいずれかに、ホバーに対応している入力デバイスが含まれる場合
`@media (any-hover: none)`|入力デバイスのいずれかに、ホバーに対応している入力デバイスが含まれる場合

### 【その4】`@media (any-pointer: 値)`

複数の入力デバイスがある場合、いずれかのポインターの精度によって判定するメディア特性です。

メディアクエリ|判定
---|---
`@media (any-pointer: fine)`|入力デバイスのいずれかに、マウスのような正確なポインターのデバイスが含まれる場合
`@media (any-pointer: coarse)`|入力デバイスのいずれかに、タッチスクリーンのようなポインターが粗いデバイスが含まれる場合
`@media (any-pointer: none)` | 上記のいずれでもない場合

## 使用例

デスクトップなどホバーに対応している場合にリンクの色を変えたい場合はこのように記載します。

```scss
@media (hover: hover){
  a {
    color: #327caf;
      &:hover {
        color: #205875;
    }
  }
}
```

### メディア特性を複数組み合わせる

`and`、 `not`、 `or` を使うことで、複数組み合わせることも可能です。

ホバーに対応していて、かつマウスのような正確なポインターが含まれているデバイスに絞り込みたい場合はこのように記載します。

```scss
@media (hover: hover) and (pointer: fine){
  a {
    color: #327caf;
      &:hover {
        color: #205875;
    }
  }
}
```

:::note
複数組み合わせるときは、毎回記載するのは大変なのでmixinなどにしておくと、呼び出しが楽になると思います。
:::

## ターゲットデバイスの例

:::note warn
必ずしも全てのデバイスに当てはまるとは限りませんので、特定の機種やデバイスをターゲットにしたい場合は実機確認をおこなってください。
:::

参考 [7. 対話媒体に関する特能 | Media Queries Level 5 （日本語訳）](https://triple-underscore.github.io/mediaqueries5-ja.html#mf-interaction)

### :iphone:スマートフォンなどのタッチスクリーンの場合

```scss
@media (hover: none) and (pointer: coarse){
  a {
    color: #327caf;
      &:active {
        color: #205875;
    }
  }
}
```

### :pencil2:  タブレットなどのスタイラスペンでの操作の場合

```scss
@media (hover: none) and (pointer: fine){
  a {
    color: #327caf;
      &:active {
        color: #205875;
    }
  }
}
```

### :iphone: タブレットもスマートフォンも統一したい場合

```scss
@media (hover: none) and (any-pointer: coarse){
  a {
    color: #327caf;
      &:active {
        color: #205875;
    }
  }
}
```

### :video_game:Wiiのリモコンなどのモーション・コントローラーの場合

```scss
@media (hover: hover) and (pointer: coarse){
  a {
    color: #327caf;
      &:hover {
        color: #205875;
    }
  }
}
```

### :mouse_three_button:デスクトップなどでマウス使う場合

```scss
@media (hover: hover) and (pointer: fine){
  a {
    color: #327caf;
      &:hover {
        color: #205875;
    }
  }
}
```

### :keyboard:デスクトップなどでキーボードを使う場合

```scss
@media (hover: none) and (pointer: none){
  a {
    color: #327caf;
      &:active {
        color: #205875;
    }
  }
}
```

## まとめ

1.メディア特性を利用する

メディア特性|役割|値
---|---|---
hover|ホバーが可能か判定する|`hover`, `none`
pointer|入力デバイスの精度を判定する| `fine`, `coarse`, `none`
any-hover|複数の入力デバイスのいずれかがホバーが可能か判定する|`hover`, `none`
any-pointer|複数の入力デバイスのいずれかの入力デバイスの精度を判定する| `fine`, `coarse`, `none`

2.メディア特性は`and`、 `not`、 `or` を使って、複数組み合わせることができる

## おわりに

ここまで読んでいただきありがとうございました。
あなたが提供したいUIに合わせて、メディア特性を組み合わせてみてください。

明日の[Qiita株式会社 Advent Calendar 2021](https://qiita.com/advent-calendar/2021/qiita)は、 @tomoasleep が担当します！ :santa: