🎄Open UI Advent Calendar: Day 10 / Customizable Select Element Ep.8

Published on December 10, 2024

Customizable Select Elementの関連仕様: `appearance: base-select;` - 選択された`<option>`のデフォルトチェックマークのスタイルはどうやって決まったのか

Table of Contents

Table of Contents

はじめに

Customizable Select Element Ep.8では、<selectmenu>を経て、<selectlist>から<select>に至るまでの経緯をお話ししました。

端的にまとめると、初期 Explainer で使用されていた<selectmenu>は、主に UI パターンの観点から混乱を招くことが懸念され、Open UI 内での議論を以って<selectlist>に変更されました。

その後、<selectlist>の実装の方針や Progressive Enhancement の観点から、<select>の機能を拡張する形で実装した方が良いのではないかという議論が行われ、2024/9 月に<select>として RFC が発表されるに至ります。

Request for developer feedback: customizable select  |  Blog  |  Chrome for Developers
An early look at the new customizable select feature.
Request for developer feedback: customizable select  |  Blog  |  Chrome for Developers favicon developer.chrome.com
Request for developer feedback: customizable select  |  Blog  |  Chrome for Developers

Customizable Select Elementの関連仕様

各パーツの定義

CSE の各パーツは、RFC が出された時点から大きく変化しています。 (2024/12/9 現在)

2024/12/9時点でのselectの各パーツの定義 2024/12/9時点でのselectの各パーツの定義

appearance: base-select;

<select>を CSE に Opt-in するには、CSSappearanceプロパティを使用します。次のように、<select>::picker(select)appearance: base-select;を指定することで、<select>を CSE にアップグレードすることができます。

select, ::picker(select) {
  appearance: base-select;
}
<select>
  <option>Option 1</option>
  <option>Option 2</option>
  <option>Option 3</option>
</select>

上記の HTML と CSS で、CSE が Opt-in され、<select>CSEデフォルトのスタイルになります。

CSEデフォルトのスタイル CSEデフォルトのスタイル

ここで気になるのが、「何を以てこのデフォルトのスタイルになったのか」です。

選択された<option>のチェックマーク

CSE デフォルトのスタイルでは、選択された<option>にチェックマークがついています。チェックマークは、CSE でなくても(appearance: base-select;を設定しない<select>でも)ついていますが、CSE のデフォルトスタイルを決める段階では、「チェックマークが必要か」「どういった実装にするべきか」という議論が行われました。


まず、「チェックマークが必要か」に関してです。

チェックマークを提供しないことになった場合、コントラスト比の観点からアクセシビリティの問題が生じる可能性があるとの指摘がありました。

チェックマークがなく、選択肢ポップオーバーの背景色とポップオーバー内部の背景色のコントラスト比が低い場合、選択された要素を明示するために非常に強い色の背景色をつけるなどの対策が必要になります。そうなった場合、フォーカスインジケータとのコントラスト比が低くなる可能性が出てきます。

つまり、「チェックマークを提供しない」という選択肢をとった場合、「選択肢ポップオーバーの背景色 vs ポップオーバー内部の背景色 vs フォーカスインジケータのボーダー色」という3つの色のコントラスト比のバランスを考慮する必要があるということになります。 その点、チェックマークを提供すると、選択された要素を明示することができるため、選択肢ポップオーバーの背景色とポップオーバー内部の背景色のコントラスト比を気にする必要がなくなり、幾分かコントラスト比の考慮が緩和されるということです。

加えて、単一選択<select>の時点で、チェックマークを考慮しておくと、チェックマークの提供が必ず必要になってくる複数選択<select>の実装においても役立つという理由がありました。


次に、「どういった実装にするべきか」に関して追っていきます。 チェックマークをどのように UA スタイルシートに実装するかに関して、Issueの時点では次のように実装されることが望ましいとされました。

option::marker {
  content: '\2713' / '';
}
option:not(:checked)::marker {
  visibility: hidden; /* visibility: hiddenにすることで幅を保てる */
}

チェックマークが擬似要素で実装されているのは、DOM にチェックマークを実装するのではなく、CSS 擬似要素で実装することで、ユーザがより簡単に上書きや削除する(カスタマイズする)ことが可能だからです。

擬似要素と言っても、::before::afterは更なるスタイリングを施すために用いたいというケースも考えられるため、新しい擬似要素が定義されることになりました。

RESOLVED: create new pseudo elements for checkmark and dropdown icon for base appearance select instead of using ::before and ::after in the UA stylesheet https://github.com/w3c/csswg-drafts/issues/10908#issuecomment-2371836734

その上で、次に注目すべき点は、擬似要素のcontent'\2713' / ''となっていることです。

筆者は知らなかったのですが、contentプロパティはスラッシュ(/)区切りで alt テキストを指定することができ、これが明示してある場合は、contentプロパティの前半が表示され、後半は alt テキストとして AT に読み上げられるようです。(ブラウザによって alt テキストは表示もされるそうですが、未確認です)

上記の実装により、AT はcontentプロパティによる読み上げをせず、選択された<option>の checked 属性による読み上げのみしてくれるので、重複した読み上げが起こりません。

加えて、絵文字の「✔︎」などを使用するのではなく、標準化された Unicode でチェックマークを表現することにより、OS の慣習に追従した、一貫性のある表示を実現できます。

RESOLVED: support checkmark next to checked option, implemented via the content property on the ::marker pseudo element. The UA should set a Unicode character by default, which isn’t read out by screen reader. https://github.com/openui/open-ui/issues/863#issuecomment-2127775634


上記の議論時点では::markerでしたが、一旦 Chromium には付け焼き刃的に::before実装され、RFC 公開時点ではそのまま::beforeで、2024/12 現在では::checkmarkに変わり、次の UA スタイルシートが実装されています。

RESOLVED: Name the pseudo-element ::checkmark https://github.com/w3c/csswg-drafts/issues/10908#issuecomment-2489173316

select option::checkmark {
  content: '\2713' / '';
}
select option:not(:checked)::checkmark {
  visibility: hidden;
}
select::picker-icon {
  /* margin-inline-start pushes the icon to the right of the box */
  margin-inline-start: auto;
  display: block;
  content: counter(fake-counter-name, disclosure-open);
}

chrome canaryで::checkmarkのUAスタイル chrome canaryで::checkmarkのUAスタイル

CSE のデフォルトスタイルに関しては、次の Issue で現在進行形で更新が重ねられており、Chromium ではこの Issue の変更に追従する形で実装が進められているようでした。


Issue によると主に次の項目に着目できそうで、今回はその一部であるチェックマークに関して取り上げました。

上記 Issue に記されているデフォルトスタイルになった背景について、次回からも引き続き見ていこうと思います。

それでは、また明日⛄

See you tomorrow!

Appendix