🎄Open UI Advent Calendar: Day 17 / Customizable Select Element Ep.15

Published on

Updated on

Customizable Select Elementの関連仕様: `<selectedcontent>` - `slot`属性と`behavior`属性が使用廃止を受け、CSE Anatomyが改訂。HTML史上初となる、UAからLight DOMへ変更を加える実装検討へ

Table of Contents

Table of Contents

はじめに

Ep.14では、<selectlist>slot属性とbehavior属性の使用が廃止された経緯をお話ししました。slot属性とbehavior属性は「選択された<option><button>にスロットしてカスタマイズできるようにする」ための手段だったのですが、この手段が廃止されたことにより、これからどう話が進むのかをみていきます。

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

Customizable Select Elementの関連仕様

ここまでの整理

ここまでの経緯を一旦整理しておきます。slot属性とbehavior属性が廃止されるまで、主に 4 つの Issue が関連しあっていました。

という流れを辿って、<selectedvalue>が提案されるところまで来ました。

新しい<selectlist>のAnatomy

slot属性とbehavior属性の廃止後に出された新しい Explainer では、Issueでのコメントに基づき、次のような Anatomy となりました。

slot属性とbehavior属性の廃止によりでた差分のみにフォーカスしてみます。

  • button (slot) - The portion of the element which is rendered in the position of the button which opens the listbox. It should contain a button to open the listbox. If this part is not provided by the author, then <selectlist> will automatically create one. All child elements of the <selectlist>, except <listbox>, <option>s, and <optgroup>s will be slotted into this slot.
  • <button type=selectlist> - The button which opens the listbox when clicked. The type=selectlist attribute indicates to the browser that this button should open the listbox.
  • <selectedvalue> - The element which contains the text of the currently selected option. Every time that the user selects an option, the browser will replace the text content of this element with the text content of the selected option.
  • <listbox> - The wrapper that contains the <option>(s) and <optgroup>(s). If this part was not provided by the author, then <selectlist> will automatically create one.

  • button (slot) - listboxが開くbuttonが配置されるスロット部分。このスロットには、listboxを開くためのbuttonが配置される。もしAuthorがこの部分を提供しない場合、<selectlist>が自動的に作成する。<selectlist>の子要素で、<listbox><option><optgroup>以外の全ての要素は、このスロットに配置される
  • <button type=selectlist> - クリックされたときにlistboxを開くbutton。type=selectlist属性値は、このボタンがlistboxを開くことをブラウザに示す。
  • <selectedvalue> - 現在選択されているoptionのテキストを含む要素。ユーザがoptionを選択するたびに、ブラウザはこの要素のテキストコンテンツを選択されたoptionのテキストコンテンツで置き換える。
  • <listbox> - <option><optgroup>を含むラッパー。もしAuthorがこの部分を提供しない場合、<selectlist>が自動的に作成する。

使用例も、次のようになっています。

<selectlist>
  <button type="selectlist">
    <span>selected option:</span>
    <selectedoption></selectedoption>
  </button>
  <listbox>
    <option>one</option>
    <option>two</option>
  </listbox>
</selectlist>

この差分を見る限り、かなり現在の CSE の仕様に近い形になったように見えます。

しかし、この段階では、<selectedvalue>は選択された<option>の中身をまるっとクローンしてくる現在の仕様とは異なり、まだ単にプレーンテキストで置換するのみというふうに読み取れます。

要素クローンの話はどうなったのかを探る前に、<selectedvalue>は”<selectedvalue>”ではなくなるので、一旦軽く確認しておきます。

<selectedvalue><selectedoption>

そもそも<selectedvalue>で提案されたのは、以前同等の機能を持っていたが、behaviorの廃止とともに消えてしまったbehavior=selected-value属性値に由来するためでした。

上記 Issue では、<selectedoption>が有力候補として挙げられ、特に大きな反対もなく、<selectedoption>が採用されてExplainerに反映されます。


ここで再び、元々選択された<option>のクローンが検討された背景のあるIssueに戻ります。

ここで Jarhar が提案した、「プレーンテキストだけではない、選択された<option>の中身をまるっとクローンする<selectedoption>の実装」が、HTMLで初めて採用される実装の出発点でもあり、現在の<selectedcontent>の元となります。

(※ これ以前の時点で、<selectedmenu><selectlist>に変更されているので、この先は<selectlist>と記述します)

選択された<option>の子要素を<selectedoption>にクローンする提案の再出発

Jarjar のコメントが非常によくまとまっているので、この節はコメントを意訳したものです。

この提案は、Mason Freed と Domenic と話し合われた結果、至った結論のまとめです。

TL;DR: ブラウザが、選択された<option>の内容を<selectedoption>cloneNode()して、その子Nodeを置き換えるべきだと考えている。標準化に向けてより良い解決策が見つかれば、それに切り替えることも考えているが、現在は、ChromiumでcloneNode()を用いたプロトタイプを実装している。

次に、上記結論の過程で考慮された、実装方針の比較検討をしています。

1. 選択された<option>の子Nodeを<selectedoption>のShadowRootにクローンする

<selectedoption>は UA の ShadowRoot を持ち、選択された<option>が変わるたびに<selectedoption>の ShadowRoot のすべての子を削除し、<option>cloneNode()して、そのクローンの各子 Node を<selectedoption>ShadowRootに追加します。

また、Author 側から UA ShadowRoot 内の<selectedoption>のスタイルをする上で、<selectedoption>の ShadowRoot 内のコンテンツをターゲットに指定するための、::selectedoption()のような疑似要素を提供する必要があります。

これは、SVG の<use>の使い方に似ています。

この手法の問題点:

2. 選択された<option>の子Nodeを<selectedoption>のLight DOMにクローンする

1 のように、クローン先に ShadowRoot を持つ代わりに、<selectedoption>の Light DOM 子 Node をクローンされた Node で置き換えます。

この手法の問題点:

3. CSSでコンテンツを内部的にミラーリングするためのelement()のサポート

Firefox は CSS でコンテンツをミラーリングする方法を実装しています:

element() - CSS | MDN
The element() CSS function defines an <image> value generated from an arbitrary HTML element. This image is live, meaning that if the HTML element is changed, the CSS properties using the resulting value are automatically updated.
element() - CSS | MDN favicon developer.mozilla.org
The MDN logo

これと同等の機能を実装し、選択された<option>のレンダリング結果を<selectedoption>にミラーリングすることができます。

この手法の問題点:

4. Magical mirroring

3 のような、単なる画像としてのミラーリングではなく、選択された<option>の子 Node が<selectedoption>Flat treeまたはLayout treeにも現れるようにミラーリングする方法を見つけることができるかもしれません。

類似のアイデアが提案されていますが、同じものを意図するかは不明です: <mirror> element, like <slot>, but not limited to ShadowDOM, elements from anywhere can be assigned to it · Issue #6507 · whatwg/html

この手法の問題点:

5. あきらめて全員にスクリプトを追加させる

「Light DOM へのクローン」を実現するために必要な、次のようなスクリプトを開発者に提供します:

selectlist.addEventListener("change", () => {
  while (selectedoption.firstChild) {
    selectedoption.firstChild.remove();
  }
  for (const newChild of selectmenu.selectedOption.cloneNode(true)) {
    selectedoption.appendChild(newChild);
  }
  selectedoption.className = selectmenu.selectedOption.className;
});

この手法の問題点:


このように、一口にクローンすると言ってもさまざまな手法が考えられ、それぞれに pros/cons があることがわかります。単にクローンするにしても Light DOM にクローンするのか、Shadow DOM にクローンするのかに判断の余地があったり、ミラーリングは実装や DOM 的な懸念があったりします。

これに対して、Domenic は、クローンによる Light DOM の変更というのは前例のないことではあるが、このユースケースを達成するための唯一の合理的な選択肢であると考えている、とフィードバックします。

Light DOM に別の要素の Light DOM をクローンすると、<selectedoption>は具体的には次のような挙動をすることになります。

次の図では、選択された<option>の子 Node が、<selectedoption>Light DOMにクローンされる様子を示しています。
Light DOM に直接挿入されるため、クローンされた要素は、Author Style Sheet の適用が可能となります。

UAによってLight DOMにクローンされたNodeが直接挿入される様子
UAによってLight DOMにクローンされたNodeが直接挿入される様子

こうした、要素が自身の Light DOM を変更するという挙動は、他の長年の HTML 機能に対するリクエストを解決するためにも必要かもしれないと Domenic は述べます。

例えば、上記のように、UA が Light DOM を変更して良いのであれば、これまで実現できなかった次のようなユースケースもカバーできるようになるかもしれません:

Domenic は、この実装によって、プラットフォームが長年苦しんできた「Light DOM は完全に Author の領域であり、UA スクリプトによって変更されるべきではない」という制約に対して、今回意識的にその境界を越えることができれば、今後の新しい選択肢が開けるかもしれないという証拠を提供したい、と述べています。


こうして、<selectedoption>の提案が再スタートを切り、選択された<option><selectedcontent>の Light DOM にクローンする仕様が策定&実装されていくことになります。

HTML 史上初となる、UA から Light DOM へのクローン追加実装。CSE のみならず、HTML の新たな可能性を切り開くきっかけと言え、非常に興味深いものとなっていきそうです!

次回からは、この<selectedoption>について、どのような実装上の課題があり、どう解決されていくのかを見ていきます。

それでは、また明日⛄

See you tomorrow!

Appendix