ウェブコンポーネント


先月私はビルで働き始めたaccessible Web Components . これは、最小限のビルドツールと依存関係を必要とするアクセス可能でスタイリッシュなWebコンポーネントを生成するための長期的なプロジェクトの一部であり、また、正規の要素を操作するための同様の開発者の経験を提供します.
それ以来、他の仕事の間で、私はスタイリングWebコンポーネントの現在の状態を見てきました.
スタイリングの問題は、実際にWebコンポーネントを使用する機能の一つによって引き起こされますShadow DOM . これは、通常のDOMとWebコンポーネントの間で、スクリプトやスタイルの交差を制限するコンテナのように動作します.Webコンポーネントを任意のプロジェクトに配置することができます個別の単位を許可します.残念なことに、これは開発者がプロジェクトにWebコンポーネントを組み込むことを試みる能力が非常に限られたスタイルコントロールを持っていることを意味します.
一方、Webコンポーネントを使用して開発者がスタイルコントロールを行うことを可能にする一方で、その種のコントロールを意図的にし、コンポーネントのデザインを考慮して、外部スタイルシートがラフになっているだけではないように注意する必要があります.
したがって、スタイリングWebコンポーネントの現在の状態は、どのように行うことができますか?

読書


Webコンポーネントは2011年に導入されましたが、一般的なサポートはしばらくかかりました.時間とともに、スタイルに利用できるアプローチはシフトして、進化しました.
  • Smashing Magazine 2016年に利用できる様々な手法について書きました.
  • CSS Tricks また、2021年1月(最近12月に更新されました)で最も最近で、記事のいくつかを書きました.
  • いくつかの他の良い読み取りはこれですexplainer on CSS Shadow ::part and ::themeblog post by Nolan Lawson .
  • 最初の単純な/素朴な試み-失敗


    私の目的の1つはウェブコンポーネントを使用して開発者のための摩擦の最小量を作成することでした.
    私の以前のブログ記事では、私がデザインした方法について書きました<dropdown-selector> 人に似て働く<select> , 特にオプションがどのように要素に加えられたかについて.
    <dropdown-selector>
        <option>First choice</option>
    </dropdown-selector>
    
    なぜなら、その内容は<dropdown-selector> コンポーネントの独自のHTMLに置き換えられたので、レンダリングされませんでした、私はおそらく私は同様のことを行うことができると思った<style> 要素と私が持っていたようにそれを引く<option> 要素
    <dropdown-selector>
        <option>First choice</option>
    
        <style>
            * {
              background-color: #ccffcc;  
            }
        </style>
    </dropdown-selector>
    
    残念ながら、スタイルはWebコンポーネントの外のすべてに適用されました.

    ( ab )メディアセレクタを使用して成功する


    かなり大きな読書をして、考えて、他のものに取り組んで、ちょうど問題に戻るのを避けた後に、私は突然考えを持っていました.特定の状況を除いて、適用されないスタイルを作成する方法があり、開発者やデザイナーは常にそれを使用します.
    メディアセレクタ<style media="print"> or @media print , 例えば.私はその上で新鮮になった@media rule そして、私はそれが良い考えであると確信していませんでしたが、特に私が私が考えたことをすることができなかったと言う何かがあったように思えませんでした.
    基本的に、その考えは私には次のようなことができるということがわかった.
    <style media="dropdown-selector">
        * {
            background-color: #ccffcc;
        }
    </style>
    
    または
    @media dropdown-selector {
      * {
        background-color: #ccffcc;
      }
    }
    
    トリッキーなビットは、それらのスタイルを要素に注入する方法です.

    CSSオブジェクトモデル


    JavaScriptを介してドキュメント内のHTMLにアクセスしたり変更したりできるDOM APIがあるように、CSSOM .
    オープンシャドウDOMを使用しているWebコンポーネントで動作する場合、DompdownのオプションをプルするためにDOMにアクセスしたのと同じ方法で、親ドキュメントのCSSOMにアクセスできます.
    Array.from(document.styleSheets).forEach((outerStyleSheet) => {
      if (Array.from(outerStyleSheet.media).includes('dropdown-selector')) {
        const styleSheet = document.createElement('style');
        this.shadowRoot.appendChild(styleSheet);
    
        Array.from(outerStyleSheet.cssRules).forEach((cssRule) => {
          styleSheet.sheet.insertRule(cssRule.cssText);
        });
    
        return;
      }
    
      if (Array.from(outerStyleSheet.cssRules).find((cssRule) => {
        return cssRule.media && Array.from(cssRule.media).includes('dropdown-selector');
      })) {
        const styleSheet = document.createElement('style');
        this.shadowRoot.appendChild(styleSheet);
    
        Array.from(outerStyleSheet.cssRules).forEach((cssRule) => {
          if (cssRule.media && Array.from(cssRule.media).includes('dropdown-selector')) {
            Array.from(cssRule.cssRules).forEach((cssRule) => {
              styleSheet.sheet.insertRule(cssRule.cssText);
            });
          }
        });
      }
    });
    
    あらゆる<style> ドキュメント内の要素は以下のリストでアクセス可能ですdocument.styleSheets , そして、それらのスタイルシートの各々はmedia プロパティ自体がリストであり、スタイルをドロップダウンに適用しているかどうかを確認できます.
    正しいスタイルシートを見つけるときmedia プロパティは、元のスタイルシートからルールを新しいものにコピーします<style> コンポーネントの影DOMに追加する要素.
    私も、いつでも検索するコードを入れます@media ルールは、任意のスタイルシート内で使用され、範囲内のルールをコピーします.
    これは動作していた-私は今、コンポーネントの元の組み込みスタイルをオーバーライドする任意のスタイルを適用することができます.しかし、私は特にメディアセレクターのこの使用に熱心でありませんでした-ブラウザー自体は文句を言われませんでした、そして、それは働いていました、しかし、それはちょうど右に座りませんでした.
    一方、日は終わっていて、夕食の時間でした.それで、私はコードを概念の証明として、そこに残しました.

    後見解の明白


    一歩戻って、何かをすることは、開発者のためのスーパーパワーです.なぜなら、たとえあなたが問題について積極的に考えていなくても、あなたの脳はある種のバックグラウンドプロセスにそれを入れることができます.その後、適切な条件の下で、新しい視点がバブルアップすることができます.
    それで、ちょうど真夜中ごろ、私がベッドサイドの本を置いて、ランプを消したように、私は、私が全くメディアセレクタを必要としなかったとわかりました.開発者に任意のトリッキーな構文を使用する必要がなく、既存のHTML/CSS属性の悪用を必要としない別の完全に許容できるソリューションがありました.
    ' dropdownセレクタ'という名前の新しいカスタム要素を追加します.CSSはセレクタとして使うことができます.
    dropdown-selector * {
      background-color: #ccffcc;
    }
    
    それから、セレクタとして含めるCSS規則を探すことができました.
    Array.from(document.styleSheets).forEach((outerStyleSheet) => {
      Array.from(outerStyleSheet.cssRules).forEach((cssRule) => {
        if (cssRule.selectorText && cssRule.selectorText.startsWith('dropdown-selector')) {
          const rule = cssRule.cssText.replace('dropdown-selector ', '');
    
          styleSheet.sheet.insertRule(rule);
        }
      });
    });
    
    これは、我々が前にしていたことを単純化する利点があります.

    クラスとIDセレクタによる特定のスタイリング


    開発者/デザイナーがすべてのドロップダウンセレクタに一般的なスタイルを適用したい場合は上記の解決策はうまくいきます.しかし、彼らがクラスまたはIDセレクタで特定のスタイルを目標にしたいならば、どうですか?
    <dropdown-selector id="months" class="groovy funky">
    
    </dropdown-selector>
    

    IDセレクタ


    これは2つのより簡単です.
    要素が与えられたmonths , 我々は、使用するすべての規則を引き出すことができます#months セレクタで.私たちがしなければならない唯一のことは#months コンポーネントのシャドウDOM内のルート要素にマッチするセレクタを指定します.
    Array.from(document.styleSheets).forEach((outerStyleSheet) => {
      Array.from(outerStyleSheet.cssRules).forEach((cssRule) => {
        // ...
    
        if (this.id && cssRule.selectorText.startsWith(`#${this.id}`)) {
          const rule = cssRule.cssText.replace(`#${this.id} `, '#root ');
    
          styleSheet.sheet.insertRule(rule);
        }
      });
    });
    
    したがって、IDによるドロップダウンを選択するスタイルは、適用されます.
    #months {
      background-color: #ccccff;
    }
    

    クラスセレクタ


    IDセレクタが実装するのが比較的簡単である間、それが単一である(そして、うまくいけば)ユニークな値であるので、クラスセレクタはトリッキーになるでしょう.要素は複数のクラスに属することができます.クラスセレクタもスタックできます.this.that .
    まず、ドロップダウンセレクタ要素のクラスをコピーします.
    Array.from(this.classList).forEach((cssClass) => {
      this.__root.classList.add(cssClass);
    });
    
    それから、任意の適用規則を引くだけです.
    Array.from(document.styleSheets).forEach((outerStyleSheet) => {
      Array.from(outerStyleSheet.cssRules).forEach((cssRule) => {
        // ...
    
        Array.from(this.classList).forEach((cssClass) => {
          console.log(cssClass);
          if (cssRule.selectorText.includes(`.${cssClass}`)) {
            styleSheet.sheet.insertRule(cssRule.cssText);
          }
        });
      });
    });
    
    再び、これは開発者/デザイナーが以下のようなCSS規則を入れたとき、同じ特殊性が適用されます.
    .groovy.funky {
      background-color: #ffccff;
    }
    

    更なる仕事


    したがって、概念の証拠として、これは確かに動作します.私はそれが行われた仕事だと思いません、そして、私は途中で端ケースがあると確信します.
    例えば、より複雑なセレクタ#some-form dropdown-selector .option 必ずしも現在の解決策では動作しません.
    また、CSSにメディアセレクタと新しいレイヤー機能の問題があります.このような規則を選ぶことができ、適切に適用する必要があります.
    @media (prefers-color-sceme: dark) {
      dropdown-selector {
        background-color: #003300;
      }
    }
    
    私も、私のプロジェクトで多くのTuwind風CSSを使用します-しかし、これまで、私はバニラCSSを使うことに私自身を制限しました.それで、私はTarwind CSSとうまく動作する解決策を考え出す必要があります.他のCSSフレームワークもたくさんあります.
    もう一つのこと:Webコンポーネントがドキュメント内で使用されるたびに、このコードをスタイルで引っ張るのは効率的ではありません.ですから、この種のコアを有効にするコードで作業する必要があるようです.
    旅は続く.