CSS

select要素のデザインを思い通りに整える|主要ブラウザで崩れないCSS設計

みなと
UI実装担当
UI実装担当

デザインカンプどおりに実装したいのに、ブラウザごとにselectの見た目が全然違う…。

select要素(プルダウンメニュー)は、フォームパーツの中でも「見た目を整えづらい」ことで有名です。枠線や背景の色を変えるだけなら簡単そうに見えますが、ブラウザやOSによって微妙に見た目が変わってしまいます

特に、右端の矢印アイコンや立体的な質感などは、ブラウザが独自に描画している部分のため、
思いどおりにカスタマイズするのが難しく感じやすいところです。

でも、コツをつかめば大丈夫。
この記事では、その“整え方のコツ”を分かりやすく解説していきます。

optionリスト(開いた中身)まで含めて見た目を統一したい場合は、JavaScriptで独自のセレクトボックスを作る必要があります。今回はそこまで踏み込まず、「中身はそのままに、閉じた状態のselectをCSSで整える方法」を紹介します。

なぜselectの装飾は難しいのか

select要素の装飾は、CSSの中でも「思ったように反映されにくい」要素のひとつです。同じHTMLとCSSを書いても、ブラウザによって細かな見た目や挙動が異なる──その違いが、selectを扱うときに難しさを感じる原因となります。

ブラウザごとに見た目が異なる

特に、デフォルト状態のselectを表示した場合、ブラウザによって見た目に意外と差があります。

  • Chrome … 角がやや丸く、影付き
  • Safari … シンプルでフラットな表示
  • Firefox … 矢印が独自デザイン
  • Edge … WindowsのシステムUIに近い見た目

これらは、ブラウザやOSがそれぞれ独自のデフォルトスタイルを適用しているためです。そのため、何も指定していない状態で見た目が統一されず、ユーザー環境によって印象が変わってしまいます。

各OS・ブラウザでのselect要素の初期表示比較。Windows、macOS、iPadOS、iOS、Androidそれぞれで、右端の矢印や背景の立体感などが異なることを示した図。
同じHTMLでも、ブラウザによって初期状態の見た目はこんなに違います。

初期状態がブラウザごとに差があるため、幅やフォントサイズなどを少し指定するだけでは、完全に同じ見た目には揃いません。

開いたリスト部分はカスタマイズできない

先ほども少し触れましたが、selectを開いたときのリスト部分(option一覧)は、CSSで自由に装飾することはできません。

このリストは、ブラウザではなくOSが持つ「選択メニューの仕組み」を使って表示されています。そのため、背景色や角丸、影などをCSSで指定しても反映されず、macOS・Windows・LinuxなどのOSごとに見た目が異なります。

たとえば:

  • macOSではフラットで影のないメニュー
  • Windowsでは立体感のある選択ハイライト
  • 一部環境ではスクロールバーの色や形まで違う

このように、開いたリスト部分はブラウザを超えてOSが管理する領域です。そのため、HTMLやCSSで自由にデザインをコントロールすることはできません。

CSSでselectをデザインする考え方

ここまでで、selectの装飾が思ったようにいかない理由が見えてきました。では、閉じた状態のselectを、どのブラウザでも違和感なく整えるにはどうすればよいでしょうか。

ポイントは次の2つです。

差をなくしてからデザインを整える

selectをデザインするときは、ブラウザ独自の装飾をリセットしてから装飾を行うことを意識しましょう。

ブラウザやOSごとに、selectには微妙に異なる初期スタイルが設定されています。そのまま上からCSSを当てても、角丸や背景、影のつき方などが一致せず、見た目に差が生まれてしまいます。

この差をなくすために使うのが appearance: none;。標準の矢印や立体的な装飾を消してフラットな状態に戻し、そのうえで borderbackgroundpadding などを指定して整えていきます。

スワン
スワン

appearance: none; は、ブラウザが自動で適用している標準の装飾を無効化するCSSです。

これによって、どのブラウザでも同じような見た目で表示できるようになります。

select要素だけで完結させようとしない

select には、テキストや枠線のほかに右端の矢印など、複数の見た目要素が含まれます。デザインによっては、select要素単体では思い通りの見た目に整えにくいこともあります。そのため、select要素だけで装飾を完結させず、親要素や周囲の要素を組み合わせてデザインを補完するのが現実的です。

たとえば──

  • select の外側にラッパー要素を設けて枠線や影を付ける
  • 矢印などのアイコン部分を別の要素で表現する
  • 背景グラデーションや余白などを親要素側で制御する

といったように、役割を分担して見た目を組み立てるのがポイントです。

完成デモの紹介

ここまでの考え方をもとに、主要ブラウザで崩れず、見た目を統一できるselectデザインを作成しました。ブラウザの初期装飾をリセットし、右端の矢印を別要素で表現することで、枠線・背景・テキストをシンプルに整えた構成になっています

実際のコード構成を見ながら、どのように組み立てているのかを確認していきましょう。各部分の役割やポイントも合わせて解説します。

コード全体(HTML / CSS)

ここからは、デモで使用しているHTMLとCSSの全体コードを確認していきます。全体の構成を把握したうえで、このあとにポイントを順に解説していきます。

HTMLコード

まずはHTMLです。シンプルな構造で、selectをラッパー要素で囲み、右端の矢印部分を別要素で表現しています。

<!-- セレクトボックス全体を囲むコンテナ -->
<div class="select-box">

  <!-- 商品カテゴリを選択するセレクトメニュー -->
  <select name="category">
    <option value="">商品カテゴリを選択してください</option>
    <option value="living">リビング・ダイニング用品</option>
    <option value="bath">バス・サニタリー用品</option>
    <option value="kitchen">キッチン・調理用品</option>
    <option value="storage">収納・整理グッズ</option>
    <option value="outdoor">アウトドア・レジャー用品</option>
  </select>

  <!-- CSSで装飾するための矢印パーツ -->
  <div class="select-box-arrow"></div>
</div>

CSSコード

続いてCSSです。ブラウザごとの差をリセットしつつ、select本体と矢印要素を役割分担してデザインを整えています。サイズや余白はメディアクエリで調整し、PC・スマホの両方で自然に見えるようにしています。

/* セレクトボックス全体のラッパー要素 */
.select-box {
  position: relative; /* 子要素の絶対配置の基準にする */
}

@media print, (min-width: 768px) {
  .select-box {
    width: 500px;
    height: 75px;
    margin: 0 auto;
  }
}

@media screen and (max-width: 767px) {
  .select-box {
    height: 55px;
  }
}

/* セレクト本体の装飾 */
.select-box select {
  display: block;
  position: absolute; /* 親要素内で全体に広げる */
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  box-sizing: border-box;
  border: 1px solid #84cbe3;
  border-radius: 8px;
  background: linear-gradient(0deg, #d0ebf5, #fff); /* 上下の淡いグラデーション */
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.2); /* 立体感を出す影 */
  color: inherit;
  font: inherit;
  font-weight: 700;
  line-height: 1.5;
  outline: none; /* デフォルトのフォーカス線を消す */
  appearance: none; /* ブラウザ標準の矢印を非表示にする */
  cursor: pointer;
  transition: border-color 300ms ease, box-shadow 300ms ease; /* ホバー・フォーカス時のアニメーション */
}

@media print, (min-width: 768px) {
  .select-box select {
    padding: 0 50px 0 30px;
    font-size: 23px;
  }
}

@media screen and (max-width: 767px) {
  .select-box select {
    padding: 0 35px 0 20px;
    font-size: 16px;
  }
}

/* ホバー・フォーカス時の強調 */
.select-box select:hover,
.select-box select:focus {
  border-color: #058ad5;
  box-shadow: 0 3px 30px rgba(5, 138, 213, 0.4); /* 光を受けたような効果 */
}

/* 右側の矢印部分(装飾専用) */
.select-box-arrow {
  position: absolute;
  right: 0;
  top: 0;
  height: 100%;
  border-top-right-radius: 8px;
  border-bottom-right-radius: 8px;
  background: linear-gradient(0deg, #058ad5, #2da3e4); /* 縦方向の青いグラデーション */
  pointer-events: none; /* ユーザー操作を透過させる */
}

@media print, (min-width: 768px) {
  .select-box-arrow {
    width: 50px;
  }
}

@media screen and (max-width: 767px) {
  .select-box-arrow {
    width: 35px;
  }
}

/* 矢印(三角形)の描画 */
.select-box-arrow::before {
  content: "";
  display: block;
  position: absolute;
  left: 50%;
  top: 50%;
  background: #fff;
  clip-path: polygon(0 0, 100% 0, 50% 100%); /* 下向き三角形を描く */
  transform: translate(-50%, -50%); /* 中央に配置 */
}

@media print, (min-width: 768px) {
  .select-box-arrow::before {
    width: 14px;
    height: 12px;
  }
}

@media screen and (max-width: 767px) {
  .select-box-arrow::before {
    width: 10px;
    height: 8px;
  }
}

コードのポイント解説

ここからは、実装の中で特に押さえておきたいポイントを紹介します。selectのデザインを安定させるうえで、どのような工夫をしているのかを順に見ていきましょう。

ポイント1:ラッパー要素で配置の基準をつくる

.select-box では、position: relative; を指定しています。これは、子要素(右側の矢印パーツなど)を position: absolute; で配置するときの基準となる位置をつくるためです。

.select-box {
  position: relative; /* 子要素の絶対配置の基準にする */
}

@media print, (min-width: 768px) {
  .select-box {
    width: 500px;
    height: 75px;
    margin: 0 auto;
  }
}

@media screen and (max-width: 767px) {
  .select-box {
    height: 55px;
  }
}

この指定があることで、後述の矢印をselectの右端に正しく重ねて配置できます。

ポイント2:appearance: none; でブラウザの装飾をリセット

ブラウザは、select要素に自動で立体感や矢印などの装飾を適用します。これをそのままにしてCSSを当てると、ブラウザごとに見た目が揃わなくなるため、まず appearance: none; を指定してデフォルトの装飾をリセットします。

ただし、appearance: none; だけでは完全に初期化されません。ブラウザによって borderbackgroundpadding などの初期値が微妙に異なるため、これらも合わせて明示的に指定しておくことが重要です。

.select-box select {
  display: block;
  position: absolute; /* 親要素内で全体に広げる */
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  box-sizing: border-box;
  border: 1px solid #84cbe3;
  border-radius: 8px;
  background: linear-gradient(0deg, #d0ebf5, #fff); /* 上下の淡いグラデーション */
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.2); /* 立体感を出す影 */
  color: inherit;
  font: inherit;
  font-weight: 700;
  line-height: 1.5;
  outline: none; /* デフォルトのフォーカス線を消す */
  appearance: none; /* ブラウザ標準の矢印を非表示にする */
  cursor: pointer;
  transition: border-color 300ms ease, box-shadow 300ms ease; /* ホバー・フォーカス時のアニメーション */
}

@media print, (min-width: 768px) {
  .select-box select {
    padding: 0 50px 0 30px;
    font-size: 23px;
  }
}

@media screen and (max-width: 767px) {
  .select-box select {
    padding: 0 35px 0 20px;
    font-size: 16px;
  }
}

ポイント3:矢印は別要素で描画する

ブラウザごとに select の矢印は見た目が異なり、CSSで自由に形や位置を変えることはできません。そのため、まず appearance: none; でブラウザ標準の矢印を消し、新たに矢印用の要素を自分で作成するのがおすすめです。

今回のデモでも、右端の矢印を .select-box-arrow という要素で表現しています。

<div class="select-box">
  <select>…</select>
  <div class="select-box-arrow"></div>
</div>
.select-box-arrow {
  position: absolute;
  right: 0;
  top: 0;
  height: 100%;
  border-top-right-radius: 8px;
  border-bottom-right-radius: 8px;
  background: linear-gradient(0deg, #058ad5, #2da3e4); /* 縦方向の青いグラデーション */
  pointer-events: none; /* ユーザー操作を透過させる */
}

@media print, (min-width: 768px) {
  .select-box-arrow {
    width: 50px;
  }
}

@media screen and (max-width: 767px) {
  .select-box-arrow {
    width: 35px;
  }
}

/* 矢印(三角形)の描画 */
.select-box-arrow::before {
  content: "";
  display: block;
  position: absolute;
  left: 50%;
  top: 50%;
  background: #fff;
  clip-path: polygon(0 0, 100% 0, 50% 100%); /* 下向き三角形を描く */
  transform: translate(-50%, -50%); /* 中央に配置 */
}

@media print, (min-width: 768px) {
  .select-box-arrow::before {
    width: 14px;
    height: 12px;
  }
}

@media screen and (max-width: 767px) {
  .select-box-arrow::before {
    width: 10px;
    height: 8px;
  }
}

pointer-events: none; を指定しているのは、矢印の上をクリックしてもselectが正常に開くようにするためです。また、clip-pathを使ってCSSだけで矢印形状を描画しており、画像を使わず軽量に実装しています。

clip-path の使い方をもっと詳しく知りたい方は、こちらの記事で解説しています

あわせて読みたい
CSSで複雑な形も簡単設定!実務でも使えるclip-pathの基本形状と応用例を紹介
CSSで複雑な形も簡単設定!実務でも使えるclip-pathの基本形状と応用例を紹介

まとめ

select要素は、見た目を自由に変えるのが難しい要素ですが、
「ブラウザ差をリセットしてから整える」
「矢印などの装飾は別要素に分けて表現する」
という2つの考え方を押さえておくだけで、扱い方がぐっと簡単になります。

今回紹介した方法は、どのブラウザでも同じように表示でき、デザインに合わせて調整しやすいシンプルな構成です。

実務でも応用しやすい構成なので、ぜひ自分のプロジェクトに合わせてアレンジしてみてください!

押していただけると励みになります!

ABOUT ME
みなと
みなと
フロントエンドエンジニア
東京のWeb制作会社で15年以上働いている現役フロントエンドエンジニアです。これまで、いろんなプロジェクトに関わりながら、フロントエンド開発やWebデザインに取り組んできました。このブログでは、今までの経験を活かして、Web制作に役立つ情報やノウハウをシェアしていきたいと思います。初心者の方から、現場で働く方まで、誰でも参考にできる内容をお届けしますので、ぜひ覗いてみてください。
記事URLをコピーしました