CSS プロパティ appearance: base-select を使用すると、<select> 要素とその選択ツール(::picker(select) 経由)を通常の HTML 要素のようにスタイル設定できます。Grid や Flexbox などの最新の CSS レイアウト手法と組み合わせることで、従来の縦に並んだリストから脱却し、カスタム JS を使用せずに豊かな視覚体験を実現できます。たとえば、display: grid を使用して、オプションをカードの 2D グリッドとしてスタイル設定できます。
これは、カラー選択ツール、絵文字セレクタ、バリエーション商品など、リストよりも視覚的に豊かなメニューの方が効果的な場合に最適です。
実装方法
1. 基本スタイリングを有効にする
<select> 要素とその内部ピッカー疑似要素 select::picker(select) の両方に appearance: base-select を適用します。
select.grid-picker {
&, &::picker(select) {
appearance: base-select;
}
}
2. 選択ツールのコンテナのスタイルを設定する
select:open::picker(select) をターゲットにして、display: grid(または display: flex)を適用します。他のコンテナと同様に、列とギャップを定義します。
select.grid-picker:open::picker(select) {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
}
重要: :open は必須です。select::picker(select) のスタイルを設定すると、選択が閉じているときでも選択ツールが表示されます。
3. オプションのスタイルを設定する
<option> 要素をターゲットにして、グリッド アイテムまたはカードとしてスタイルを設定します。
内部に画像、SVG、複雑なレイアウトを追加できます。
/* Style options as grid cards */
.grid-picker option {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
/* padding, border-radius, background, etc. */
}
4. 選択したオプションのスタイルを設定する
選択した option のスタイルを設定するには、option:checked を使用します。次に例を示します。
.grid-picker option:checked {
position: relative;
border: 2px solid var(--primary-color);
background-color: oklab(from var(--primary-color) l a b / 8%);
}
他の UI コントロールと同様に、色だけで状態を伝えないようにし、複数の視覚的なインジケーター(色、枠線の太さ、チェックマークなど)を使用して、どのオプションが選択されているかを伝えます。
5. (省略可)選択したオプションのチェックマークのスタイルを設定する
デフォルトでは、ブラウザは各 <option> の最初の子としてチェックマークをレンダリングします。
これは、content: "✓" / "" を含む ::before のように動作し、作成者が指定した ::before(存在する場合)の前にレンダリングされます。
オプションが選択されていない場合、チェックマークは visibility: hidden によって非表示になります。
::checkmark 疑似要素を使用してスタイルを設定することも、スタイル設定のみで選択を伝える場合やカスタム インジケーターを使用する場合は、完全に非表示にすることもできます。
たとえば、オプションの右上隅に配置するには、次のようにします。
select.grid-picker {
> option::checkmark {
/* Hide the checkmark for unselected options */
display: none;
}
> option:checked {
position: relative;
&::checkmark {
position: absolute;
inset-block-start: -.4em;
inset-inline-end: -.5em;
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
min-inline-size: 1.6em;
aspect-ratio: 1;
padding-right: 0.12em;
padding-left: 0.05em;
border-radius: 50%;
background: var(--primary-color);
color: white;
font-size: 70%;
font-weight: bold;
}
}
}
ヒント: チェックマークの周囲にコンテナ(円など)を描画する場合は、形状を考慮して視覚的に中央に配置されるように、少し上方向に移動します(ここでは padding-bottom と padding-left を使用)。この目的で padding-inline-start や padding-block-end を使用しないでください。これらは書字方向に応じて変化しますが、チェックマークの形状は変化しません。
6. (省略可)選択したオプションの表示をカスタマイズする
デフォルトでは、<select> には選択したオプションのテキストのみのバージョンが表示されます。選択した値のリッチ コンテンツを表示するには、<button> 内で <selectedcontent> を使用します。また、選択したオプションを異なる方法で表示する(特定の詳細を非表示にするなど)場合にも使用します。
<selectedcontent> を <button> で囲まずに使用しないでください。<selectedcontent> が他のコンテンツ要素と同様に、選択ツールの一部になってしまいます。
ベスト プラクティス
- レイアウトの動作をテストします。
appearance: base-selectを設定すると、最も長いオプションの幅に基づいて選択要素のサイズを決定するデフォルトのブラウザ動作が削除されます。レイアウト シフトを防ぐために、固定幅を設定するか、flex / grid 制約を使用する必要がある場合があります。 <select>にname属性と関連付けられた<label>があることを確認します。これにより、カスタム UI を使用している場合でも、コンポーネントはスクリーン リーダーにアクセス可能であり、標準のフォーム送信で正しく動作します。- オプションで標準の
value属性を使用して、フォームの送信が以前とまったく同じように機能するようにします。
ユーザー補助
ネイティブの <select> は、上下の矢印キーによる直線的なナビゲーションのみを処理するため、開いた選択ツールでは左右の矢印キーは機能せず、上下の矢印キーは行と列に関係なく、項目を順番に移動します。
グリッドに沿った空間ナビゲーションを実装するには、矢印キーが使用されたときに keydown をインターセプトし、押された方向の最も近いオプションにフォーカスをルーティングします(getBoundingClientRect() を使用するなど)。適切な次 / 前のアイテムを決定するには、grid-template-columns や grid-column などの CSS 文字列を解析するのではなく、実際のジオメトリ(getBoundingClientRect() など)を操作する DOM メソッドを使用します。CSS 文字列の解析は、複雑なグリッド、サブグリッド、RTL、その他のレイアウト シナリオでは、脆弱でエラーが発生しやすくなります。ただし、不必要に過剰な設計をしないでください。レイアウトについて真であることがわかっている不変条件を使用して、このロジックを簡素化します。
注: これはキーボード ナビゲーションにのみ対応しています。<select> とその ::picker() には、デフォルトのロール(menu または listbox)が引き続き割り当てられます。これらはオーバーライドできず、role="grid" を含む要素を含めることもできません。選択ツールの内部に role="grid" を含むラッパーをネストすることは、実際には機能しますが、有効ではなく、AT ユーザーを驚かせる可能性があります。場合によっては、<optgroup> を使用してオプションをグループ化すると、role="grid" を使用しなくても、スクリーン リーダーの UX が向上することがあります。そうでない場合は、最終的に、スクリーン リーダー ユーザーに望ましい UX を提供するために、Popover API、アンカー ポジショニング、role="grid" を使用するカスタム ソリューションに切り替える必要があります。
代替戦略
カスタマイズ可能な <select> のフォールバックとブラウザ サポート
appearance: base-select をまだサポートしていないブラウザでは、<select> 要素は標準のオペレーティング システムのプルダウンに適切にフォールバックされます。
- テキスト以外のコンテンツが無視される: 古いブラウザでは、
<option>タグ内の HTML タグ(<svg>や<div>など)が削除され、テキストノードのみがレンダリングされます。<option>のテキスト コンテンツが、それ自体で読みやすく、意味のあるものになるようにします。 - HTML 構造の処理: 標準のパーサーは、
<select>内の<button>タグと<selectedcontent>タグを無視するか、無効として扱うことがあります。標準テキストを読み取り可能なフォールバックとして表示する場合、プログレッシブ エンハンスメントに重い JavaScript ポリフィルは厳密には必要ありません。
document.addEventListener("DOMContentLoaded", () => {
// Check if browser supports base-select value
if (!CSS.supports("appearance", "base-select")) {
// Custom select overrides are not supported natively.
}
});