SELECT要素内に画像を表示させたい

## 画像付き文字を選択させるには？
html の select タグは、一種の選択肢です。
普段は選択済み要素だけが表示されていて、タグをクリックした時だけ、選択肢の内容がプルダウン形式で表示されますね。
この select は文字だけしか表示できませんが、画像も付けてあげた方が分かりやすいと思う場合もあります。例えば、言語を選ぶ時に国旗も表示したい時などがそうですね。
ところが、これがなかなか手強いのです。

## (1) 選択済みの時だけ、画像も表示
まずは、選択済みの時だけ画像も表示してみましょう。
やることは以下の通りです。

- select の background-image を使う事で画像を表示させます。
background-repeat: no-repeat 指定も必要です。

- 文字は padding を使って、画像と重ならない位置に移動させます。

- safari では select には css が効かないそうなので、safari のみ appearance を button 外観にします(🔽表示が消えますが仕方ありません)。

- select 選択肢が変更されたら、javascript を使って background-image を変更。これを実現するため、option の value で画像ファイル名を指定します。

こうですね。
（背景色を設定しているのは日本国旗を見えやすくする為なので、国旗でなければ不要です）
<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="css,result" data-user="phoophiang" data-slug-hash="BajEBeb" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="SelectWithImg">
  <span>See the Pen <a href="https://codepen.io/phoophiang/pen/BajEBeb">
  SelectWithImg</a> by Hiroaki Okabe (<a href="https://codepen.io/phoophiang">@phoophiang</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

コツとしては、画像の縦サイズを全て揃えておき、その縦サイズより2px大きい値を height に指定すること。および、font-size を画像縦サイズより2px以上(3pxを推奨)小さく設定することです。font-size は普通なら px 単位での設定をするべきでは無い(remを使うべき)ですが、ここでは画像サイズに合わせることを優先します。
また実際に使う時には、select自体の位置指定とかも必要だと思います。

## (2) 選択中も、画像を表示
(1)の方法では、select をクリックした時に出る選択肢には画像が表示されていません。
では同じように、option タグにも background-image を指定してやれば良いだろうと誰もが考えるのですが… 残念ながら、効きません。before を使ってもダメです。
いろいろ試してみた結果、select を使う限りは表示できないという結論に達しました。

select が使えないなら、自分で select モドキを実装するしかありません。以下のようにします。

- 選択済み(1行だけ)の表示と、プルダウンを開いた時の2つを別々に作ります。
プルダウンは選択済みの上に重ねて表示します。このようにしないと、プルダウンが開いた時にページのサイズが変わってしまうことがあります。

- 選択済みとプルダウンの両方を table で作ります。
これは javascript の一部共通化と、画像とテキストの縦方向を中央に揃えやすくする目的の2つが理由です。

- 選択済みがクリックされたら選択済みの onclick を消す。プルダウンが閉じられたら onclick を付ける。

- プルダウン選択中のアイテムが分かりやすいように、hover 設定。

- プルダウンが開いている時に、外側がクリックされたらプルダウンを閉じる。

こんな感じです。
(ES6未満でも使えるようにしておいたつもりですが、ES6未満では動作未検証です。すみません)

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="js,result" data-user="phoophiang" data-slug-hash="vYLMYYz" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="imitationSelect">
  <span>See the Pen <a href="https://codepen.io/phoophiang/pen/vYLMYYz">
  imitationSelect</a> by Hiroaki Okabe (<a href="https://codepen.io/phoophiang">@phoophiang</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

html 部分では選択済みの table だけ作っておき、この table の id と選択肢の内容を Array で指定して渡して呼びます(Javascriptの最後の部分を参考にしてください)。
CSSでは画像サイズに応じた設定が必要です。プルダウン表示時は、タブレットでも選択しやすいように縦幅を広げてあげると親切です。
![画像付きSELECT](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181201/f1c0aa9d-e837-3de2-d305-776aaee01b18.png)

## スマホとPCで使い分ける(?)
選択肢に画像を表示させたいなら(2)の方法だけで十分なように思いますが、実はスマホでは(1)を使った方が良いと思うのです。
スマホでは select をタップすると、タップした位置では無く、画面下部などで選択肢の横幅が広がって選べるようになってます。iOS(safari)では画面が拡大され、android(Chrome)では選択肢以外が暗くなるなどの工夫も凝らされています。
![スマホでのSELECT](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181201/85ba3aea-fd13-228c-4028-dfffe02bce4d.jpeg)
この方が広い面積で選べるので、画面が小さいスマホでは select を使ってあげた方が利便性が上がります。
ただ、スマホとPCで html を大きく変更するのは面倒かもしれません。
この場合、(2)の方法を使い、スマホだと画面下部いっぱいにプルダウンを表示してやるみたいな対応も考えられます。ここまでスクリプトが作ってあれば簡単かと思いますので、必要な人は作り込んでみてください（私はそこまで必要じゃ無かったです ^^;）。

## 最後に
この画像付きSELECTを作るのに一番苦労したのは、実は縦方向のセンタリングでした。
ググれば対応方法はいろいろ見つかりますが、言語選択のように小さな部品では、1ドットの差でも違和感が出てしまいます。
table を使うのがベストだと気付いた後も試行錯誤しました。td の height に 16px を指定しているにも関わらず 24px とかで表示されてしまうのです。td が充分に大きい時には気付かないのですが、小さい時は文字列の line-height の影響を受けると分かるまで時間がかかりました。

この縦方向の試行錯誤のせいで、どうも余計な(無意味な) CSS 指定をしている気もします。気が付かれた方がいましたらご指摘ください。

私は、自分で作ったスマホアプリの公式サイトで、この画像付き選択を使っています。スマホとPCでは別ページになっていて、スマホ用ページでは(1)を、PCでは(2) を使っています。見た目の問題で、国旗の画像もスマホ用の方がPCよりも小さくしています。
サイトの言語選択なので、選択されたら対応ページに飛ぶようにしていますので、ここで紹介したスクリプトとは若干違いますが、ご興味があれば訪問して頂ければ幸いです(宣伝です)。

- 竹本泉はじめてのスマホゲーム「人魚Days」　[PC用ページ](https://mermaiddays.com/pc/jp/index.html)　[スマホ用ページ](https://mermaiddays.com/mob/jp/index.html)