💄

HTMLのselect要素がCSSでカスタマイズ可能になる

2024/09/29に公開

select 要素がカスタマイズできるようになる

これまで HTML の<select>要素はカスタマイズが難しい部分でした。各ブラウザのデフォルトスタイルに依存しデザインや機能を統一するのが困難でした。かといってオリジナルのセレクトボックスを作成するとなると CSS と JavaScript でイチから作成する必要がありました。

しかし今後、HTML ネイティブの<select>要素に柔軟にスタイルを加えることができるようになるようです。イチから作成したセレクトボックスをネイティブのselect要素と同等レベルでアクセシビリティやパフォーマンスに配慮して、各 OS に最適化されたユーザー体験にするのは至難の業ですので、ネイティブ<select>要素がカスタマイズできるということは革命的なことだと思います。

本記事では、実際に<select>要素のカスタマイズ機能が先行的に実装されている Canary 版の Chrome を使用して、カスタマイズ機能を試した様子を紹介していきます。

https://developer.chrome.com/blog/rfc-customizable-select

概要

まず、セレクトボックスのベーススタイルとして<select>要素と::picker(select)appearance: base-select を指定します。こちらを指定することで以下画像の右のようなベーススタイルを全ブラウザで適用することができます。

/* ベーススタイル適用 */
select,
::picker(select) {
  appearance: base-select;
}


左:appearance: base-select未適用、右:appearance: base-select適用

あとはセレクトボックスの各パーツごとに要素や疑似要素が割り振られているので、カスタマイズしたい要素に CSS を当てることで、カスタマイズすることができます。

詳細のカスタマイズ方法は公式のブログをご覧ください。

実際に使ってみる

早速<select>要素のカスタマイズして、実際のサイトで使われているセレクトボックスを再現していきます。

今回は

の 2 つのサイトのセレクトボックスを再現していきます。

実際に試す ① Chrome for Developers

まず Chrome for Developers のヘッダーのセレクトボックスを再現していきます。

地球儀のアイコンや、選択中のoption、フォーカス・ホバーされているoptionの色、サイズや角丸の大きさや枠線などを反映していきます。

HTML
<select>
  <button>
    <svg
      aria-hidden="true"
      class="icon-language"
      viewBox="0 0 24 24"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path
        d="M12 22q-2.05 0-3.875-.788-1.825-.787-3.187-2.15-1.363-1.362-2.15-3.187Q2 14.05 2 12q0-2.075.788-3.887.787-1.813 2.15-3.175Q6.3 3.575 8.125 2.787 9.95 2 12 2q2.075 0 3.887.787 1.813.788 3.175 2.151 1.363 1.362 2.15 3.175Q22 9.925 22 12q0 2.05-.788 3.875-.787 1.825-2.15 3.187-1.362 1.363-3.175 2.15Q14.075 22 12 22Zm0-2.05q.65-.9 1.125-1.875T13.9 16h-3.8q.3 1.1.775 2.075.475.975 1.125 1.875Zm-2.6-.4q-.45-.825-.787-1.713Q8.275 16.95 8.05 16H5.1q.725 1.25 1.812 2.175Q8 19.1 9.4 19.55Zm5.2 0q1.4-.45 2.487-1.375Q18.175 17.25 18.9 16h-2.95q-.225.95-.562 1.837-.338.888-.788 1.713ZM4.25 14h3.4q-.075-.5-.113-.988Q7.5 12.525 7.5 12t.037-1.012q.038-.488.113-.988h-3.4q-.125.5-.188.988Q4 11.475 4 12t.062 1.012q.063.488.188.988Zm5.4 0h4.7q.075-.5.113-.988.037-.487.037-1.012t-.037-1.012q-.038-.488-.113-.988h-4.7q-.075.5-.112.988Q9.5 11.475 9.5 12t.038 1.012q.037.488.112.988Zm6.7 0h3.4q.125-.5.188-.988Q20 12.525 20 12t-.062-1.012q-.063-.488-.188-.988h-3.4q.075.5.112.988.038.487.038 1.012t-.038 1.012q-.037.488-.112.988Zm-.4-6h2.95q-.725-1.25-1.813-2.175Q16 4.9 14.6 4.45q.45.825.788 1.712.337.888.562 1.838ZM10.1 8h3.8q-.3-1.1-.775-2.075Q12.65 4.95 12 4.05q-.65.9-1.125 1.875T10.1 8Zm-5 0h2.95q.225-.95.563-1.838.337-.887.787-1.712Q8 4.9 6.912 5.825 5.825 6.75 5.1 8Z"
      ></path>
    </svg>
    <selectedoption></selectedoption>
    <svg
      aria-hidden="true"
      class="icon-arrow"
      viewBox="0 0 24 24"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path d="m12 15-5-5h10Z"></path>
    </svg>
  </button>
  <option selected>English</option>
  <option>Nederlands</option>
  <option>Русский</option>
  <option>فارسی</option>
  <option>বাংলা</option>
</select>
CSS
/* セレクトボックスのボタン部分 */
button {
  display: flex;
  column-gap: 8px;
  align-items: center;
  height: 36px;
  padding: 0 7px 0 11px;
  background-color: #fff;
  border-radius: 4px;
  border: 1px solid #e8eaed;
  cursor: pointer;
  height: 36px;
}
button:hover,
button:focus-visible {
  outline: none;
}

.icon-language {
  block-size: 24px;
  inline-size: 24px;
}

.icon-arrow {
  block-size: 24px;
  inline-size: 24px;
}

/* ベーススタイル */
select,
::picker(select) {
  appearance: base-select;
}

/* ドロップダウン部分全体のスタイル */
::picker(select) {
  border-radius: 2px;
  box-shadow: 0 1px 2px 0 hsla(0, 0%, 87%, 0.16), 0 2px 6px 2px rgba(60, 64, 67, 0.15);
  position: absolute;
  left: -100px;
}

/* option要素のスタイル */
option {
  padding: 0 16px;
  height: 48px;
  font-size: 14px;
  cursor: pointer;
}

/* 選択されているoption要素のスタイル */
option:checked {
  background: #e8f0fe;
}

/* 選択されているoption要素のbefore要素(チェックマーク) */
option::before {
  display: none;
}

/* ホバー・フォーカスされているoption要素のスタイル */
option:hover,
option:focus-visible {
  background-color: #f5f6f7;
  outline: none;
}


実際に select 要素をカスタマイズ

かなり再現することができました。
また<select>要素ネイティブの機能も失っていないので、(上記の Gif 画像だと分かりにくいのですが)矢印キーで選択できたり、テキスト入力で選択が補完されたりします。(Eと入力したら English が選択される)

実際に試す ② Notion

次に Notion のセレクトボックスを再現していきます。今回はライトテーマ・ダークテーマ設定のセレクトボックスを例に再現していきます。

① と同様に選択中のoptionのチェックマーク、フォーカス・ホバーされているoptionの色、サイズや角丸の大きさや枠線などを反映していきます。

HTML
<select>
  <button>
    <selectedoption></selectedoption>
    <svg
      role="graphics-symbol"
      viewBox="0 0 30 30"
      class="chevronDown"
      style="
            width: 10px;
            height: 100%;
            display: block;
            fill: rgba(55, 53, 47, 0.35);
            flex-shrink: 0;
            margin-left: 4px;
          "
    >
      <polygon points="15,17.4 4.8,7 2,9.8 15,23 28,9.8 25.2,7 "></polygon>
    </svg>
  </button>
  <option selected>システム設定を使用する</option>
  <option>ライトテーマ</option>
  <option>ダークテーマ</option>
</select>
CSS
/* カスタマイズ可能にするためのベーススタイル */
select,
::picker(select) {
  appearance: base-select;
}

/* セレクトボックスのボタン部分 */
button {
  background-color: #fff;
  cursor: pointer;
  height: 28px;
  border: none;
  border-radius: 6px;
  font-size: 14px;

  display: flex;
  column-gap: 4px;
  align-items: center;
  padding-left: 8px;
  padding-right: 8px;
  color: rgb(55, 53, 47);
}
button:hover,
button:focus-visible {
  background-color: rgba(55, 53, 47, 0.06);
  outline: none;
}

/* ドロップダウン部分全体のスタイル */
::picker(select) {
  border-radius: 10px;
  background: white;
  position: relative;
  box-shadow: rgba(15, 15, 15, 0.05) 0px 0px 0px 1px, rgba(15, 15, 15, 0.1) 0px 3px 6px,
    rgba(15, 15, 15, 0.2) 0px 9px 24px;
  min-width: 250px;
}

/* option要素のスタイル */
option {
  margin: 0 4px;
  padding: 0 16px;
  min-height: 28px;
  font-size: 14px;
  cursor: pointer;
}

/* 選択されているoption要素のbefore要素(チェックマーク) */
option::before {
  position: absolute;
  right: 16px;
  content: "";
  display: inline-block;
  width: 14px;
  height: 14px;
  background-size: contain;
  background-repeat: no-repeat;
  background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" role="graphics-symbol" viewBox="0 0 14 14" class="check" style="width:100%25;height:100%25;display:block;fill:inherit;flex-shrink:0;"%3E%3Cpolygon points="5.5 11.9993304 14 3.49933039 12.5 2 5.5 8.99933039 1.5 4.9968652 0 6.49933039"%3E%3C/polygon%3E%3C/svg%3E');
}

/* ホバー・フォーカスされているoption要素のスタイル */
option:hover,
option:focus-visible {
  background-color: rgba(55, 53, 47, 0.06);
  outline: none;
}


実際に select 要素をカスタマイズ

Notion セレクトボックスも概ね再現することができましたが、::picker(select)要素(ドロップダウン部分)を横方向に展開することができませんでした。

まとめ

今回ネイティブの<select>要素のカスタマイズを実際に試して、完全とは言わないまでも、かなり柔軟にカスタマイズできるようになることが分かりました。

現在、<select>要素のカスタマイズはフィードバックが募られており、更に改善していくと思われます。まだ検証できていない他の OS や他のブラウザでの動作も気になります。<select>要素のカスタマイズ機能の今後に注目していきたいです。

Discussion