ハイライト
Safari 27 と Chrome 135 は、ネイティブの
<select>要素にappearance: base-selectや::picker(select)などの疑似要素を追加しました。開発者は純粋な CSS だけでドロップダウンの見た目を完全にカスタマイズでき、<option>の中に画像や SVG も置けます。それでもキーボードナビゲーションとスクリーンリーダー対応は自動で保たれます。
主要内容
Web フォームを作る人は、ほぼ必ず <select> に悩まされてきました。デザイナーがアイコン、角丸、影の付いたドロップダウンを描くと、フロントエンド側はすぐ頭を抱えます。ネイティブの <select> がどんな見た目になるかは OS が決めます。macOS では青地に白文字の pull-down button 風、Windows ではまた別の見た目です。変えたい場合は、Headless UI や Select2 のような数十 KB の JS ライブラリを入れて大量の <div> でドロップダウン動作を模倣するか、自作してキーボードナビゲーション、フォーカス管理、ARIA ラベルを手で実装するしかありません。実装が終わっても、VoiceOver と NVDA で一つずつ確認する必要があります。
今はこの道がかなり通りやすくなりました。Safari 27 と Chrome 135 は Customizable Select を同時に提供し、その中核思想は「HTML タグはそのまま、CSS だけを追加する」です。<select> に appearance: base-select を 1 行加えると、ブラウザはボタンとドロップダウンパネルのスタイル固定を解除し、開発者に制御を戻します。<option> には <img>、<svg>、さらには <video> も直接入れられます。さらに重要なのは、これらの変更がすべてセマンティック HTML の上に成立していることです。上下キーでの移動、Enter での選択、スクリーンリーダーの読み上げはすべてネイティブ対応のままで、追加コードは不要です。
Session では写真家のポートフォリオサイトが例として示されました。クライアントはページに並べ替えとカテゴリフィルタを追加したいので、<select> でドロップダウンを作ります。しかしネイティブコントロールをそのまま置くと、サイト全体のデザインから浮いてしまいます。Customizable Select を使うと、ボタンの背景、枠線、角丸、内側余白をすべて CSS でカスタマイズでき、ドロップダウン矢印はカスタム SVG に置き換えられ、メニュー展開中にはボタン色も切り替えられます。この改修全体は数行の CSS だけで済みます。
詳細
カスタマイズモードを有効にする
(02:50)
最初の手順は、<select> に appearance: base-select を追加することです。このプロパティはブラウザに対して、システム既定の見た目ではなく、開発者が上書きしやすい最小限のベーススタイルを使うよう伝えます。
body {
font-family: Gill Sans, sans-serif;
}
select {
appearance: base-select;
}
ポイント:
appearance: base-selectは親要素のフォント設定を継承するため、ボタン上の文字はページ内の他のテキストと自然に揃います。- このプロパティは Safari 専用ではなく、Chrome 135 も対応しています。prefix は不要です。
ボタンの見た目をカスタマイズする
(03:07)
ベーススタイルを有効にすると、通常のボタンを書くように CSS を書けます。
select {
appearance: base-select;
background-color: var(--green-10);
border: none;
padding: 0.6em 1em;
}
ポイント:
background-color、border、padding、border-radiusなどの通常プロパティが<select>に完全に効くようになります。!importantも、ブラウザ既定スタイルシートへの hack も不要です。
ドロップダウン矢印を置き換える
(03:08)
ブラウザ既定のドロップダウン矢印は、::picker-icon 疑似要素で置き換えられます。
select::picker-icon {
content: url(icons/arrow.svg);
width: 0.65em;
}
メニューが開いている間は、ボタンと矢印の状態を切り替えられます。:open 疑似クラスを使います。
select:open {
background-color: var(--green-100);
color: white;
}
select:open::picker-icon {
content: url(icons/arrow-white.svg);
}
ポイント:
::picker-iconは Customizable Select で追加された疑似要素で、ドロップダウン矢印の制御に特化しています。:open疑似クラスはメニュー展開中に一致します。JavaScript でfocusやblurを監視する手間を省けます。
ドロップダウンパネルをカスタマイズする
(04:08)
ドロップダウンメニュー本体もカスタマイズできます。::picker(select) でパネルを選び、同じく appearance: base-select を追加すると、システムスタイルを完全に解除できます。
::picker(select) {
appearance: base-select;
padding: 4px;
margin-top: 0.5em;
border: 1px solid rgba(0, 0, 0, 0.2);
border-radius: 9px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
}
ポイント:
::picker(select)内のappearance: base-selectは必須です。書かないと、パネルはシステム既定の白地に黒枠のままです。margin-topでパネルとボタンの間隔を制御できます。
オプションの見た目をカスタマイズする
(04:36)
選択状態と既定のチェックマークも変更できます。
option:checked {
font-weight: 600;
}
option:not(:checked) {
color: #777;
}
option::checkmark {
content: url(checkmark.svg);
width: 0.65em;
}
ポイント:
option:checkedは現在選択中のオプションを選び、option:not(:checked)はそれ以外のオプションを選びます。::checkmark疑似要素は選択項目の前にあるチェックマークを制御し、contentで任意の SVG に置き換えられます。
オプションに画像を入れる
(05:31)
Customizable Select では、<option> の中に画像やラベルのようなリッチコンテンツを置けます。
<option value="flower">
<img src="flowers.svg" alt="">
<span class="text">花</span>
</option>
ポイント:
<option>の内部に任意の HTML 要素を含められるようになりました。alt=""は必ず書きます。書かないと、スクリーンリーダーが画像説明と「花」のテキストを二重に読み上げる可能性があります。
既定のチェックマークを消し、背景色で選択項目を強調します。
option::checkmark {
display: none;
}
option:checked {
background: #00857e;
color: white;
}
Grid レイアウトでオプションを並べる
(06:20)
オプションが多いと、単一列のドロップダウンは長くなります。::picker(select) は display: grid に対応するため、ドロップダウンパネルをそのままグリッドにできます。
::picker(select) {
display: grid;
grid-template: 1fr 1fr / 1fr 1fr 1fr;
gap: 1rem;
}
ポイント:
grid-template: 1fr 1fr / 1fr 1fr 1frは 2 行 3 列を表します。- この Grid レイアウトはドロップダウンパネル内部にだけ作用し、ページの他の要素には影響しません。
選択中のリッチコンテンツをボタン上に表示する
(07:11)
ネイティブの <select> ボタンは、既定では純粋なテキストだけを表示します。<option> に画像が含まれていても、選択後のボタンには画像が表示されません。これを解決するには、<select> の中にカスタム <button> を置き、その中へ <selectedcontent> 要素を入れます。
<select>
<button>
<selectedcontent></selectedcontent>
</button>
<option value="anywhere">
<img src="icons/all.svg" alt="">
<span class="text">すべて</span>
</option>
<option value="buildings">
<img src="icons/buildings.svg" alt="">
<span class="text">建物</span>
</option>
<option value="flowers">
<img src="icons/flower.svg" alt="">
<span class="text">花</span>
</option>
</select>
ポイント:
<button>は<select>の最初の子要素でなければなりません。<selectedcontent>は空要素です。ブラウザが現在選択されている<option>の DOM 構造を自動的に複製して入れます。- 以前の HTML では
<button>を<select>内に置けませんでしたが、Customizable Select はこの制限を緩和しました。
プログレッシブエンハンスメント
(07:53)
Customizable Select に対応していないブラウザでは、<select> はシステム標準のドロップダウンへフォールバックします。ユーザーには慣れたプラットフォームのコントロールが表示され、キーボードナビゲーションとスクリーンリーダー機能は完全に保たれます。基盤がセマンティック HTML なので、fallback コードは不要です。
核心アイデア
-
アイコン付きの国/地域選択 UI を作る:
<option>に国旗 SVG を入れ、<selectedcontent>により選択後のボタンにも国旗を表示します。入口はappearance: base-select+::picker(select)です。 -
カラー選択 UI を作る: 各
<option>に色見本の<div>を置き、ドロップダウンパネルをdisplay: gridで 4x4 のカラーパレットにします。Session 末尾で示された放射状カラー選択 UI も同じ原理です。入口はgrid-templateレイアウト + リッチコンテンツ<option>です。 -
カテゴリフィルタコンポーネントを作る: EC サイトでよくある「カテゴリで絞り込む」は Customizable Select で実装できます。各オプションにカテゴリのアイコンと名前を入れ、選択後のボタンにもアイコンを同期表示します。入口は
<selectedcontent>+ カスタム::picker-iconです。 -
プロジェクト内の JS Select ライブラリを置き換える: React-Select や Headless UI で作った純表示系ドロップダウンをネイティブ
<select>に戻すと、依存パッケージと ARIA 保守コストを削れます。入口はプロジェクト全体でimport { Select }を検索し、置き換え可能な箇所を評価することです。 -
画像サイズ選択 UI を作る: 写真やデザインツールでよくある「サムネイル/中/原寸」のようなサイズフィルタでは、各オプションにプレビュー画像とサイズ文字を置き、グリッド配置できます。入口は
display: grid+<option>内の<img>です。
関連 Session
- CSS Grid Lanes を学ぶ - Session 内の写真家サイトの例では、画像 masonry レイアウトに Grid Lanes を使っており、Customizable Select と組み合わせると特に相性がよい。
- WebKit の新機能 - CSS と JavaScript の更新を含む、Safari 27 の他の Web プラットフォーム新機能を学ぶ。
- 空間ユーザーインターフェイスの設計原則 - カスタムドロップダウンのデザイン言語を空間コンピューティングのインターフェイスへ広げたい場合は、Apple の空間 UI 設計原則が参考になる。
- Safari と Web Apps の新機能 - 没入型 Web と PWA に関する Safari の最新進展を学ぶ。
コメント
GitHub Issues · utterances