デザイン システムとコンポーネント ライブラリでカスタム プロパティを使用するメリット。
Dave と申します。Nordhealth のシニア フロントエンド デベロッパーを務めています。私は、コンポーネント ライブラリのウェブ コンポーネントの構築など、デザイン システム Nord の設計と開発に携わっています。今回は、CSS カスタム プロパティを使用して Web Components のスタイル設定に関する問題を解決した方法と、デザインシステムやコンポーネント ライブラリでカスタム プロパティを使用するメリットについて説明します。
ウェブ コンポーネントの構築方法
ウェブ コンポーネントを構築するために、Lit を使用します。これは、状態、スコープ設定されたスタイル、テンプレートなど、多くのボイラープレート コードを提供するライブラリです。Lit は軽量であるだけでなく、ネイティブ JavaScript API 上に構築されているため、ブラウザにすでに備わっている機能を活用した、軽量なコード バンドルを提供できます。
しかし、Web コンポーネントの最も魅力的な点は、ほとんどの既存の JavaScript フレームワークで動作すること、さらにはフレームワークなしで動作することです。メインの JavaScript パッケージがページで参照されると、Web Components の使用はネイティブの HTML 要素を使用する場合と非常によく似ています。ネイティブ HTML 要素ではないことを示す唯一の明確な兆候は、タグ内にハイフンが連続して使用されていることです。これは、これがウェブ コンポーネントであることをブラウザに示す標準です。
Shadow DOM スタイルのカプセル化
ネイティブの HTML 要素に Shadow DOM があるように、Web Components にも Shadow DOM があります。Shadow DOM は、要素内のノードの非表示のツリーです。これを可視化する最善の方法は、ウェブ インスペクタを開いて [Shadow DOM ツリーを表示] オプションをオンにすることです。設定が完了したら、インスペクタでネイティブ入力要素を確認してみてください。その入力を開いて、その中のすべての要素を確認できるようになります。Google の Web Components の 1 つで試すこともできます。カスタム入力コンポーネントを検査して、Shadow DOM を確認してみてください。
Shadow DOM の利点(または欠点)の 1 つは、スタイルのカプセル化です。ウェブ コンポーネント内に CSS を記述すると、そのスタイルは漏洩してメインページや他の要素に影響を与えることはできず、コンポーネント内に完全に含まれます。また、メインページまたは親のウェブ コンポーネント用に記述された CSS が、ウェブ コンポーネントに漏洩することはありません。
スタイルをこのようにカプセル化することは、コンポーネント ライブラリのメリットです。これにより、ユーザーがコンポーネントのいずれかを使用するときに、親ページに適用されているスタイルに関係なく、意図したとおりに表示されることが保証されます。さらに確実にするために、すべてのウェブ コンポーネントのルート(「ホスト」)に all: unset;
を追加します。
ただし、Web コンポーネントを使用しているユーザーが特定のスタイルを変更する正当な理由がある場合はどうすればよいでしょうか。コンテキスト上、コントラストを高める必要があるテキストの行や、太い枠線が必要な箇所があるかもしれません。コンポーネントにスタイルを適用できない場合、スタイル設定オプションを有効にするにはどうすればよいですか?
そこで役立つのが CSS カスタム プロパティです。
CSS カスタム プロパティ
カスタム プロパティの名前は非常に適切です。これは、名前を自由に付け、必要な値を適用できる CSS プロパティです。ただし、接頭辞に 2 つのハイフンを追加する必要があります。カスタム プロパティを宣言したら、var()
関数を使用してその値を CSS で使用できます。
継承に関しては、すべてのカスタム プロパティが継承されます。これは、通常の CSS プロパティと値の一般的な動作に従います。親要素または要素自体に適用されたカスタム プロパティは、他のプロパティの値として使用できます。Google では、デザイン トークンにカスタム プロパティを多用し、CSS フレームワークを介してルート要素に適用しています。これにより、ウェブ コンポーネント、CSS ヘルパークラス、トークンのリストから値を取得するデベロッパーなど、ページ上のすべての要素でこれらのトークン値を使用できます。
var()
関数を使用してカスタム プロパティを継承できる機能により、Web Components の Shadow DOM を貫通して、デベロッパーがコンポーネントのスタイル設定をよりきめ細かく制御できるようになります。
Nord ウェブ コンポーネントのカスタム プロパティ
デザインシステムのコンポーネントを開発する際は、CSS に慎重なアプローチをとっています。無駄のない、メンテナンス性に優れたコードを目指しています。デザイン トークンは、ルート要素のメイン CSS フレームワーク内のカスタム プロパティとして定義されています。
これらのトークン値は、コンポーネント内で参照されます。値を CSS プロパティに直接適用する場合もありますが、新しいコンテキスト カスタム プロパティを定義してその値を適用する場合もあります。
また、コンポーネントに固有の値であってもトークンには含まれない値を抽象化し、コンテキスト カスタム プロパティに変換します。コンポーネントのコンテキストに応じたカスタム プロパティには、主に 2 つのメリットがあります。まず、その値をコンポーネント内の複数のプロパティに適用できるため、CSS をより「ドライ」にできます。
2 つ目は、コンポーネントの状態とバリエーションを非常にクリーンな方法で変更できることです。たとえば、ホバー状態やアクティブ状態、またはこの場合はバリエーションのスタイル設定を行う際に、変更する必要があるのはカスタム プロパティのみです。
最も大きなメリットは、コンポーネントでこれらのコンテキスト カスタム プロパティを定義すると、コンポーネントごとに一種のカスタム CSS API が作成され、そのコンポーネントのユーザーが利用できることです。
上の例は、セレクタによって変更されたコンテキスト カスタム プロパティを持つウェブ コンポーネントの例です。このアプローチ全体の結果として、実際のスタイルのほとんどを管理しながら、ユーザーに十分なスタイルの柔軟性を提供できるコンポーネントが実現します。さらに、コンポーネント デベロッパーは、ユーザーが適用したスタイルをインターセプトすることもできます。これらのプロパティのいずれかを調整または拡張する場合、ユーザーがコードを変更する必要はありません。
このアプローチは、デザインシステム コンポーネントの作成者である Google にとってだけでなく、Google のプロダクトでこれらのコンポーネントを使用する開発チームにとっても非常に強力です。
カスタム プロパティをさらに活用する
執筆時点では、これらのコンテキスト カスタム プロパティはドキュメントに記載されていませんが、開発チーム全体がこれらのプロパティを理解して活用できるように、記載する予定です。コンポーネントは npm でマニフェスト ファイルとともにパッケージ化されています。このファイルには、コンポーネントに関するすべての情報が含まれています。ドキュメント サイトがデプロイされると、マニフェスト ファイルがデータとして使用されます。これは、Eleventy とそのグローバル データ機能を使用して行われます。これらのコンテキスト カスタム プロパティは、このマニフェスト データファイルに含める予定です。
改善したい点のもう 1 つは、これらのコンテキスト カスタム プロパティが値を継承する方法です。たとえば、現在、2 つの分割コンポーネントの色を調整するには、セレクタで両方のコンポーネントを明示的にターゲットにするか、スタイル属性を使用して要素にカスタム プロパティを直接適用する必要があります。これは問題ないように思えますが、デベロッパーがこれらのスタイルを親要素またはルートレベルで定義できると、より便利になります。
カスタム プロパティの値をコンポーネントに直接設定する必要があるのは、コンポーネント ホスト セレクタを使用して同じ要素で定義するためです。コンポーネントで直接使用するグローバル デザイン トークンは、この問題の影響を受けずにそのまま渡され、親要素でインターセプトすることもできます。両方の長所を活かすにはどうすればよいですか?
限定公開カスタム プロパティと公開カスタム プロパティ
非公開カスタム プロパティは Lea Verou によって作成されたものです。コンポーネント自体のコンテキストに存在する「非公開」カスタム プロパティですが、フォールバックを使用して「公開」カスタム プロパティに設定されます。
コンテキスト カスタム プロパティをこのように定義すると、グローバル トークン値の継承やコンポーネント コード全体での値の再利用など、これまで行っていたすべてのことができます。また、コンポーネントは、そのプロパティの新しい定義を自身または親要素に正常に継承します。
この方法は厳密には「非公開」ではないという意見もあるかもしれませんが、懸念していた問題に対するエレガントな解決策であると考えております。機会があれば、コンポーネントでこの問題に取り組んで、Google が導入しているガイドラインのメリットを享受しながら、開発チームがコンポーネントの使用をより細かく制御できるようにします。
CSS カスタム プロパティで Web Components を使用する方法に関するこの分析情報がお役に立てば幸いです。ご意見をお聞かせください。また、これらの方法を自分の仕事で使用する場合は、Twitter の @DavidDarnes までご連絡ください。Nordhealth の Twitter アカウント(@NordhealthHQ)や、このデザイン システムの統合と、この記事で説明した機能の実装に尽力したチームメンバー(@Viljamis、@WickyNilliams、@eric_habich)もフォローしてください。
ヒーロー画像: Dan Cristian Pădureț