モダンCSSによるSelect要素のスタイリング
<select>要素は、常にスタイリングが最も困難なフォームコントロールの一つでした。inputやbuttonとは異なり、歴史的にOS レベルのUIコンポーネントを使用してレンダリングされてきたため、CSSで触れられるのは表面的な部分のみでした。この制限により、開発者は回避策を使用せざるを得なくなり、それらは今日でもプロダクションコードで一般的に使用されています。
本記事では、広くサポートされているappearance: noneを使用したレガシー手法と、現在モダンなChromiumブラウザで登場している新しいappearance: base-selectモデルの両方のアプローチを取り上げます。
重要なポイント
- ネイティブの
<select>要素がスタイリングに抵抗するのは、ブラウザが歴史的にレンダリングをオペレーティングシステムに委譲してきたため、プラットフォーム間で一貫性のない結果が生じるからです。 appearance: none手法は、ラッパー要素とclip-pathによるカスタム矢印を組み合わせることで、selectの閉じた状態をスタイリングする最も信頼性の高いクロスブラウザ対応の方法です。appearance: base-select(Chrome/Edge 135+)は、ドロップダウンパネル、矢印アイコン、チェックマーク、選択されたコンテンツのスタイリングフックを解放しますが、現在はChromiumベースのブラウザのみで利用可能です。@supports (appearance: base-select)を使用して、レガシーベースラインの上にモダンなアプローチをプログレッシブエンハンスメントとして重ねます。
ネイティブ<select>要素がCSSスタイリングに抵抗する理由
ブラウザは伝統的に<select>のレンダリングをオペレーティングシステムに委ねてきました。その結果、Chrome、Firefox、Safari、Edgeの間で、ボックスサイジング、フォントレンダリング、ドロップダウン矢印のスタイルが一貫性を欠き、CSSだけでそれらを統一する信頼できる方法はありませんでした。
開いたドロップダウンリスト(オプションパネル)は、今日でもほとんどのブラウザでほぼスタイリング不可能なままです。これは、アプローチを選択する前に念頭に置いておくべき重要な制約です。
レガシーアプローチ:appearance: noneとラッパー要素
select要素に対する最も広くサポートされているCSSスタイリング手法は、次の3つのステップで構成されます:
appearance: noneでネイティブの外観を取り除く<select>を自由にスタイリングできるコンテナ要素でラップするclip-pathまたは背景SVGを使用してカスタムドロップダウン矢印を追加する
:root {
--select-border: #777;
--select-arrow: var(--select-border);
}
select {
appearance: none;
background-color: transparent;
border: none;
padding: 0 1em 0 0;
width: 100%;
font-family: inherit;
font-size: inherit;
cursor: inherit;
line-height: inherit;
outline: none;
}
.select {
display: grid;
grid-template-areas: "select";
align-items: center;
position: relative;
border: 1px solid var(--select-border);
border-radius: 0.25em;
padding: 0.25em 0.5em;
background-color: #fff;
}
select,
.select::after {
grid-area: select;
}
.select::after {
content: "";
width: 0.8em;
height: 0.5em;
background-color: var(--select-arrow);
clip-path: polygon(100% 0%, 0 0%, 50% 100%);
justify-self: end;
pointer-events: none;
}
ここでのCSS gridのオーバーラップトリックは理解する価値があります:<select>と::after疑似要素の両方に同じ名前付きグリッドエリアを割り当てることでそれらを重ね、ネイティブコントロールのクリック動作を壊すことなく、カスタム矢印を視覚的に上に配置できます。
フォーカス状態については、ネイティブselectのoutlineがブラウザ間で確実に動作しないため、一般的な修正方法は<span class="focus">兄弟要素を追加し、select:focus + .focusでターゲットにしてposition: absoluteを使用して視覚的なフォーカスリングを描画することです。
このアプローチはすべてのモダンブラウザで動作し、ネイティブのアクセシビリティを保持します — キーボードナビゲーション、スクリーンリーダーのアナウンス、フォーム送信はすべて期待通りに動作します。
Discover how at OpenReplay.com.
モダンアプローチ:appearance: base-select
Chrome 135とEdge 135は、<select>の内部パーツを直接CSSスタイリングできるように公開する新しいオプトインモデルを導入しました。次のように有効化します:
select,
select::picker(select) {
appearance: base-select;
}
これにより、いくつかの新しいスタイリングターゲットが解放されます:
::picker(select)— オプションを含むドロップダウンパネル::picker-icon— ドロップダウン矢印インジケーターoption::checkmark— 選択されたオプションの横に表示されるチェックマーク:open— ピッカーが開いている間アクティブになる疑似クラスoption:checked— 現在選択されているオプションをターゲットにする
base-selectを使用すると、ピッカードロップダウンを直接スタイリングし、開閉をアニメーション化し、<selectedcontent>要素を使用して選択されたオプションのコンテンツを閉じたコントロールにミラーリングできます。サポートするブラウザでは、カスタマイズ可能なselectモデルが有効になっている場合、オプション内でよりリッチなマークアップも許可されます。
ブラウザサポート: 現在は主にChromiumベースのブラウザに限定されています。現在のステータスはCan I Useで確認してください。
プログレッシブエンハンスメントとして適用するには@supportsを使用します:
@supports (appearance: base-select) {
select,
select::picker(select) {
appearance: base-select;
}
}
どちらのアプローチを使用すべきか?
appearance: none | appearance: base-select | |
|---|---|---|
| ブラウザサポート | 95%+ | 限定的(サポート表を参照) |
| ドロップダウンパネルのスタイリング | 不可 | 可能 |
| オプション内のリッチコンテンツ | 不可 | 可能 |
| アクセシビリティ | ネイティブ | ネイティブ |
ベースラインとしてappearance: noneラッパー手法を使用してください。これはどこでも動作し、アクセシビリティを保持し、selectの閉じた状態に対する確実な制御を提供します。サポートするブラウザ向けに@supportsを使用してappearance: base-selectを上に重ねます。
まとめ
CSSによるHTMLセレクトドロップダウンのカスタマイズは、もはや「JavaScriptで完全制御」か「ブラウザのデフォルトを受け入れる」かの選択ではありません。appearance: noneラッパーパターンは、信頼できるクロスブラウザの基盤として残り、一方でappearance: base-selectは、ドロップダウンパネルのスタイリング、オプション内へのリッチコンテンツの埋め込み、ピッカーのアニメーション化への扉を開きます。これら2つの極端な間のギャップは縮まっていますが、すべてのブラウザで均一にではありません。レガシー手法から始め、モダンな手法をプログレッシブに重ね、最小限の摩擦で最も広範なユーザーをカバーしましょう。
よくある質問
いいえ。appearance noneを設定しても、オペレーティングシステムが提供する視覚的なスタイリングが取り除かれるだけです。基礎となるHTML select要素は、矢印キーによるナビゲーション、EnterとSpaceによるドロップダウンの開閉、Tabによるフォーカス移動など、すべてのネイティブキーボード動作を保持します。DOM構造は変更されていないため、スクリーンリーダーは引き続きオプションを正しくアナウンスします。
カスタマイズ可能なselect要素のサポートはまだ進化中で、ブラウザによって異なります。Chromiumベースのブラウザがこの機能を最初に実装しましたが、他のエンジンはまだ実装中です。プロダクションで使用する前に、caniuse.comで最新の互換性データを確認し、base-selectスタイルを@supports (appearance: base-select)ブロック内にラップして、サポートされていないブラウザがレガシースタイルに適切にフォールバックするようにしてください。
select要素は、ネイティブにレンダリングされる際に多くのCSSプロパティを無視します。ラッパーdivを使用することで、border、border-radius、background-color、および疑似要素によるカスタム矢印を完全に制御できます。gridオーバーラップ手法は、クリックイベントを妨げることなく矢印をselectの上に重ねます。これはselect単体では実現できません。
ラッパー上のCSS疑似要素とclip-pathを使用して、純粋にCSSで三角形の形状を描画します。疑似要素にpointer-events: noneを設定して、クリックが下のselectに通過するようにします。または、ラッパーのbackground-imageとしてインラインSVGを使用し、追加のネットワークリクエストを避けるためにdata URIとしてエンコードすることもできます。
Truly understand users experience
See every user interaction, feel every frustration and track all hesitations with OpenReplay — the open-source digital experience platform. It can be self-hosted in minutes, giving you complete control over your customer data. . Check our GitHub repo and join the thousands of developers in our community..