Google IO 2022 で発表された現在と今後のウェブ スタイリング機能に加え、その他の特典も紹介します。
2022 年は、14 の機能の実装を共同で目標に、機能と協調的なブラウザ機能リリースの両方において、CSS の最高の年となる予定です。
概要
この記事は、Google IO 2022 で行われた講演の記事形式です。各機能の詳細なガイドではなく、興味をそそる導入と簡単な概要を記載しています。深みよりも幅広さを重視しています。興味を持たれた場合は、セクションの最後にあるリソースのリンクから詳細を確認してください。
目次
以下のリストを使用して、関心のあるトピックに移動できます。
ブラウザの互換性
多くの CSS 機能が共同リリースされる主な理由は、Interop 2022 の取り組みによるものです。相互運用性の取り組みを検討する前に、Compat 2021 の取り組みを確認することが重要です。
Compat 2021
アンケートを通じてデベロッパーから寄せられたフィードバックに基づき、2021 年の目標は、現在の機能を安定させ、テストスイートを改善し、次の 5 つの機能でブラウザの合格スコアを高めることでした。
sticky
の配置aspect-ratio
のサイズ設定- レイアウト:
flex
- レイアウト:
grid
transform
の配置とアニメーション
テストスコアが全体的に向上し、安定性と信頼性が向上しました。チームの皆様、おめでとうございます。
Interop 2022
今年はブラウザが一堂に会し、開発しようとしている機能と優先事項について議論し、取り組みを一体化しました。デベロッパー向けに次のウェブ機能を提供することを計画していました。
@layer
- 色空間と関数
- 封じ込め
<dialog>
- フォームの互換性
- スクロール
- サブグリッド
- タイポグラフィ
- ビューポートの単位
- ウェブの互換性
非常に野心的なリストで、実現が楽しみです。
2022 年の新機能
当然のことながら、CSS 2022 の状態は Interop 2022 の作業に大きく影響を受けています。
レイヤをカスケードする
@layer
より前は、最後に読み込まれたスタイルが以前に読み込まれたスタイルを上書きする可能性があるため、読み込まれたスタイルの検出順序が非常に重要でした。そのため、エントリ スタイルシートは慎重に管理され、デベロッパーは重要度の低いスタイルを先に読み込み、重要なスタイルを後で読み込む必要がありました。ITCSS など、デベロッパーがこの重要性を管理できるようにするための方法論が存在します。
@layer
を使用すると、エントリ ファイルでレイヤとその順序を事前に定義できます。その後、スタイルの読み込み、読み込み、定義時にレイヤ内に配置できるため、スタイルのオーバーライドの重要性を維持しながら、慎重に管理された読み込みオーケストレーションを行う必要がなくなります。
この動画では、定義されたカスケード レイヤにより、必要に応じてカスケードを維持しながら、より自由で自由なオーサリングと読み込みプロセスを実現する方法を示しています。
Chrome DevTools は、どのレイヤからどのスタイルが来ているかを可視化するために役立ちます。
リソース
サブグリッド
subgrid
より前は、別のグリッド内のグリッドを親セルまたはグリッド線に合わせることができませんでした。各グリッド レイアウトは固有のものでした。多くのデザイナーは、デザイン全体に単一のグリッドを配置し、その中でアイテムを常に配置していますが、これは CSS では不可能です。
subgrid
以降、グリッドの子要素は親の列または行を自分のものとして採用し、それに合わせて自身または子要素を配置できます。
次のデモでは、body 要素によって 3 つの列からなる従来のグリッドが作成されます。中央の列は main
と呼ばれ、左右の列は行名
fullbleed
です。次に、本文の各要素 <nav>
と <main>
に grid-template-columns: subgrid
を設定して、本文から名前付き行を取得します。
body {
display: grid;
grid-template-columns:
[fullbleed-start]
auto [main-start] min(90%, 60ch) [main-end] auto
[fullbleed-end]
;
}
body > * {
display: grid;
grid-template-columns: subgrid;
}
最後に、<nav>
または <main>
の子要素は、fullbleed
列と main
行を使用して、自身を整列またはサイズ変更できます。
.main-content {
grid-column: main;
}
.fullbleed {
grid-column: fullbleed;
}
ラインとサブグリッドを確認するには、Devtools を使用します(現時点では Firefox のみ)。次の図は、親グリッドとサブグリッドが重ねられている様子を示しています。これで、デザイナーがレイアウトについて考えていたものに近づきました。
デベロッパー ツールの要素パネルでは、グリッドとサブグリッドの要素を確認できます。これは、レイアウトのデバッグや検証に非常に役立ちます。
リソース
コンテナクエリ
@container
より前は、ウェブページの要素はビューポート全体のサイズにのみ反応する必要がありました。これはマクロ レイアウトには適していますが、外側のコンテナがビューポート全体ではないマイクロ レイアウトでは、レイアウトを適切に調整することはできません。
@container
以降、要素は親コンテナのサイズやスタイルに応答できるようになります。唯一の注意点は、コンテナがクエリ ターゲットとして宣言する必要があることです。これは、大きなメリットを得るための小さな要件です。
/* establish a container */
.day {
container-type: inline-size;
container-name: calendar-day;
}
これらのスタイルにより、次の動画の「月」、「火」、「水」、「木」、「金」の列をイベント要素でクエリできるようになります。
calendar-day
コンテナのサイズをクエリし、レイアウトとフォントサイズを調整する CSS は次のとおりです。
@container calendar-day (max-width: 200px) {
.date {
display: block;
}
.date-num {
font-size: 2.5rem;
display: block;
}
}
もう 1 つ例を示します。ある書籍コンポーネントでは、ドラッグ先の列の使用可能なスペースに合わせて調整が行われます。
Una は、状況を新しいレスポンシブと評価しているのが正解です。@container
を使用する際には、わくわくするような有意義な設計上の決定事項が多数あります。
リソース
- コンテナクエリの仕様
- コンテナクエリの説明
- MDN でのコンテナ クエリ
- web.dev の新しいレスポンシブ
- Una によるカレンダーのデモ
- コンテナクエリのコレクション
- web.dev で Designcember を構築した方法
- Ahmad Shadeed: CSS コンテナ クエリにようこそ
accent-color
accent-color
より前は、ブランドの色に合わせたフォームを作成すると、複雑なライブラリや CSS ソリューションが作成され、管理が困難になる可能性がありました。すべてのオプションが用意され、ユーザー補助も含まれているとは言え、組み込みコンポーネントを使用するか独自のコンポーネントを採用するかを何度も選択するのは面倒です。
accent-color
の後に 1 行の CSS を追加すると、組み込みコンポーネントにブランドカラーが適用されます。ブラウザでは、色合いに加えて、コンポーネントの補助部分に対して適切なコントラストの強い色がインテリジェントに選択され、システム カラーパターン(ライトまたはダーク)に適応します。
/* tint everything */
:root {
accent-color: hotpink;
}
/* tint one element */
progress {
accent-color: indigo;
}
accent-color
の詳細については、web.dev の投稿をご覧ください。この便利な CSS プロパティの多くの側面について説明しています。
リソース
- accent-color 仕様
- MDN の accent-color
- web.dev の accent-color
- Bramus: CSS アクセント カラーでユーザー インターフェース コントロールを色付けする
色レベル 4 と 5
過去数十年、ウェブは sRGB が主流でしたが、高解像度ディスプレイや OLED や QLED 画面を搭載したモバイル デバイスが拡大するデジタルの世界では、sRGB では不十分です。さらに、ユーザーの好みに適応する動的なページが期待されており、デザイナー、デザイン システム、コード メンテナンス担当者にとってカラー マネージメントに対する関心が高まっています。
ただし 2022 年には入っていませんが、CSS には多数の新しい色関数と空間が追加されています。 - ディスプレイの HD カラー機能に対応できる色。 - 知覚の均一性など、インテントに対応する色空間。- 補間結果を大幅に変えるグラデーションの色空間。- 色関数: 混色やコントラスト、作業する空間の選択に役立ちます。
これらの色機能が登場する前は、デザイン システムは、適切なコントラスト色を事前に計算し、適度に鮮やかなパレットを確保する必要がありました。この作業はすべて、プリプロセッサまたは JavaScript が行っていました。
これらの色機能により、ブラウザと CSS がすべての処理を動的にジャストインタイムで行うことができます。テーマ設定とデータ可視化の色を有効にするために、数 KB の CSS と JavaScript をユーザーに送信する代わりに、CSS でオーケストレーションと計算を行うことができます。また、CSS は、使用前にサポートを確認したり、フォールバックを適切に処理したりするのに適しています。
@media (dynamic-range: high) {
.neon-pink {
--neon-glow: color(display-p3 1 0 1);
}
}
@supports (color: lab(0% 0 0)) {
.neon-pink {
--neon-glow: lab(150% 160 0);
}
}
hwb()
HWB は色相、白色度、黒色度の略です。色相と明るさや暗さを調整する白または黒の量のみで構成されるため、人間にとって色を表現しやすい方法です。白や黒で色を混ぜるアーティストは、この色構文の追加を高く評価するかもしれません。
このカラー関数を使用すると、HSL や RGB と同じ sRGB 色空間の色が生成されます。2022 年の新機能としては、新しい色は追加されませんが、構文とメンタルモデルを好むユーザーにとっては、一部のタスクが簡単になる可能性があります。
リソース
色空間
色の表現方法は、色空間によって決まります。各色空間には、色を扱うためのさまざまな機能とトレードオフがあります。明るい色をすべてまとめるものもあれば、明るさに応じて最初に並べるものもあります。
2022 年の CSS では、10 個の新しいカラースペースが提供されます。それぞれに独自の機能があり、デザイナーとデベロッパーが色の表示、選択、混合を支援します。以前は、色を扱う唯一のオプションは sRGB でしたが、CSS では新しい可能性と新しいデフォルトの色空間 LCH が解き放たれました。
color-mix()
color-mix()
の登場以前は、デベロッパーとデザイナーは、ブラウザが色を認識する前に、Sass などのプリプロセッサを使用して色を混ぜる必要がありました。ほとんどのカラーミキシング関数には、ミキシングを行う色空間を指定するオプションが用意されていないため、結果に混乱が生じることがあります。
color-mix()
以降、デベロッパーとデザイナーは、ビルドプロセスを実行したり JavaScript を含めたりすることなく、他のすべてのスタイルとともにブラウザで色を混ぜることができます。また、混合を行う色空間を指定することも、LCH のデフォルトの混合色空間を使用することもできます。
多くの場合、ブランドカラーをベースとして使用し、ホバー スタイルの明るい色や暗い色など、その色からバリエーションを作成します。color-mix()
の場合、次のように表示されます。
.color-mix-example {
--brand: #0af;
--darker: color-mix(var(--brand) 25%, black);
--lighter: color-mix(var(--brand) 25%, white);
}
これらの色を srgb などの別の色空間で混合する場合は、次のように変更します。
.color-mix-example {
--brand: #0af;
--darker: color-mix(in srgb, var(--brand) 25%, black);
--lighter: color-mix(in srgb, var(--brand) 25%, white);
}
以下は、color-mix()
を使用したテーマ設定のデモです。ブランドの色を変更して、テーマが更新される様子を確認します。
2022 年には、スタイルシートでさまざまなカラースペースの色を混ぜることができます。
リソース
color-contrast()
color-contrast()
より前は、スタイルシートの作成者は、アクセス可能な色を事前に把握しておく必要がありました。多くの場合、パレットでは色見本に黒または白のテキストが表示され、その色見本と適切にコントラストを付けるために必要なテキストの色を色システムのユーザーに示します。
color-contrast()
以降、スタイルシートの作成者はタスクをブラウザに完全にオフロードできます。ブラウザを使用して黒または白の色を自動的に選択できるだけでなく、デザイン システムに適した色のリストを指定して、目的のコントラスト比を満たす最初の色を選択することもできます。
以下は、色見本の色に基づいてブラウザによってテキストの色が自動的に選択される HWB カラーパレット セットのデモのスクリーンショットです。
構文の基本は次のとおりです。ここで、グレーが関数に渡され、黒と白のどちらが最もコントラストが高いかをブラウザが判断します。
color: color-contrast(gray);
この関数は、色のリストを使用してカスタマイズすることもできます。この場合、選択した色から最もコントラストの強い色が選択されます。
color: color-contrast(gray vs indigo, rebeccapurple, hotpink);
最後に、最もコントラストの高い色をリストから選択したくない場合、目標コントラスト比を指定して、最初に通過する色を選択します。
color: color-contrast(
var(--bg-blue-1)
vs
var(--text-lightest), var(--text-light), var(--text-subdued)
to AA /* 4.5 could also be passed */
);
この関数はテキストの色だけでなく、他の用途にも使用できますが、主な用途はテキストの色だと思います。適切なコントラスト色の選択が CSS 言語自体に組み込まれると、アクセシビリティに優れ、読みやすいインターフェースを提供する作業がどれほど容易になるか考えてみてください。
リソース
相対色の構文
相対色の構文を使用する前は、色の計算と調整を行うには、カラーチャネルを個別にカスタム プロパティに配置する必要がありました。この制限により、色相、彩度、明るさをすべて calc()
で簡単に調整できるため、HSL が色を操作するための主な色関数になりました。
相対色構文を使用すると、任意の空間の任意の色を分解、変更、色として返すことができます。すべて 1 行の CSS で行うことができます。HSL の制限はなくなり、必要な色空間で操作を行うことができます。また、HSL を容易にするために作成するカスタム プロパティの数も少なくて済みます。
次の構文の例では、ベースの 16 進数を指定し、それに基づいて 2 つの新しい色を作成します。最初の色 --absolute-change
はベースカラーから LCH で新しい色を作成し、クロマ(c
)と色相(h
)を維持しながら、ベースカラーの明度を 75%
に置き換えます。2 番目の色 --relative-change
はベースカラーから LCH で新しい色を作成し、今回はクロマ(c
)を 20% 減らします。
.relative-color-syntax {
--color: #0af;
--absolute-change: lch(from var(--color) 75% c h);
--relative-change: lch(from var(--color) l calc(c-20%) h);
}
色を混ぜ合わせることに似ていますが、混ぜ合わせるよりも変更に近いものです。別の色から色をキャストして、使用する色関数で名付けられた 3 つのチャンネル値にアクセスし、それらのチャンネルを調整できます。全体として、これは色の非常にクールで強力な構文です。
次のデモでは、相対色構文を使用してベースカラーの明るいバリアントと暗いバリエーションを作成し、color-contrast()
を使用してラベルのコントラストを適切に確保しています。
この関数は、カラーパレットの生成にも使用できます。指定されたベースカラーからパレット全体が生成されるデモは次のとおりです。この 1 つの CSS セットにより、さまざまなパレットがすべて強化され、各パレットがそれぞれ異なるベースを提供するだけです。ボーナスとして、LCH を使用しているため、パレットが知覚的に均一であることがわかります。この色空間により、ホットスポットやデッドスポットはありません。
:root {
--_color-base: #339af0;
--color-0: lch(from var(--_color-base) 98% 10 h);
--color-1: lch(from var(--_color-base) 93% 20 h);
--color-2: lch(from var(--_color-base) 85% 40 h);
--color-3: lch(from var(--_color-base) 75% 46 h);
--color-4: lch(from var(--_color-base) 66% 51 h);
--color-5: lch(from var(--_color-base) 61% 52 h);
--color-6: lch(from var(--_color-base) 55% 57 h);
--color-7: lch(from var(--_color-base) 49% 58 h);
--color-8: lch(from var(--_color-base) 43% 55 h);
--color-9: lch(from var(--_color-base) 39% 52 h);
--color-10: lch(from var(--_color-base) 32% 48 h);
--color-11: lch(from var(--_color-base) 25% 45 h);
--color-12: lch(from var(--_color-base) 17% 40 h);
--color-13: lch(from var(--_color-base) 10% 30 h);
--color-14: lch(from var(--_color-base) 5% 20 h);
--color-15: lch(from var(--_color-base) 1% 5 h);
}
ここまでで、色空間とさまざまな色関数を、それぞれの長所と短所に基づいてさまざまな目的に使用できることがわかりました。
リソース
グラデーションの色空間
グラデーション色空間が導入される前は、sRGB がデフォルトの色空間として使用されていました。sRGB は一般的に信頼性が高いですが、グレーのデッドゾーンなどの弱点もあります。
グラデーションの色空間の後に、色補間に使用する色空間をブラウザに指示します。これにより、デベロッパーとデザイナーは好みのグラデーションを選択できます。デフォルトの色空間も sRGB ではなく LCH に変更されます。
この構文はグラデーション方向の後に追加され、新しい in
構文を使用します。構文は省略可能です。
background-image: linear-gradient(
to right in hsl,
black, white
);
background-image: linear-gradient(
to right in lch,
black, white
);
黒から白への基本的なグラデーションです。各カラースペースの結果の範囲を確認します。一部の色は他の色よりも早く濃い黒に変化しますが、一部の色は白に変化するのが遅すぎます。
次の例では、黒がグラデーションの既知の問題空間であるため、黒が青に変化しています。ほとんどの色空間は、色補間中、または色が色空間内で A 点から B 点に移動するときに、紫色に近づきます。グラデーションは A 点から B 点まで直線で描画されるため、色空間の形状によって、パスが経由する色が大幅に変わります。
詳しい調査内容、例、コメントについては、こちらの Twitter スレッドをご覧ください。
リソース
inert
inert
の登場以前は、すぐに注意を払う必要があるページまたはアプリの領域にユーザーのフォーカスを誘導することが推奨されていました。このガイド付きフォーカス戦略は、デベロッパーがインタラクティブ スペースにフォーカスを配置し、フォーカス変更イベントをリッスンし、フォーカスがインタラクティブ スペースから離れた場合に強制的にフォーカスを戻すため、フォーカス トラッピングと呼ばれていました。キーボードまたはスクリーン リーダーを使用しているユーザーは、インタラクティブ スペースに戻るように案内され、タスクが完了してから先に進みます。
inert
の後は、ページまたはアプリのセクション全体を凍結または保護できるため、トラップは必要ありません。ドキュメントの該当部分が非アクティブの間は、クリックとフォーカスの変更ができません。これは、トラップではなく警備員のようなものです。inert
は、ユーザーをどこかにとどめておかなくても、他の場所を利用不可にすることに関心があります。
たとえば、JavaScript の alert()
関数は次のとおりです。
前の動画で、alert()
が呼び出されるまでは、マウスとキーボードでページにアクセスできることを確認してください。アラート ダイアログ ポップアップが表示されると、ページの残りの部分がフリーズしました(inert
)。ユーザーのフォーカスはアラート ダイアログ内に配置され、フォーカスを移動できる場所はありません。ユーザーが操作してアラート関数リクエストを完了すると、ページは再びインタラクティブになります。inert
を使用すると、デベロッパーは同じガイド付きの集中体験を簡単に実現できます。
動作を示す簡単なコードサンプルを次に示します。
<body>
<div class="modal">
<h2>Modal Title</h2>
<p>...<p>
<button>Save</button>
<button>Discard</button>
</div>
<main inert>
<!-- cannot be keyboard focused or clicked -->
</main>
</body>
ダイアログがその一例ですが、inert
はスライド式サイドメニューのユーザー エクスペリエンスなどにも役立ちます。ユーザーがサイドメニューをスライドアウトしたときに、マウスやキーボードでその背後のページを操作できるようにすることはできません。これはユーザーにとって少し扱いづらいものです。代わりに、サイドメニューが表示されているときはページを無効にします。これにより、ユーザーはサイドメニューを閉じるか、サイドメニュー内で移動する必要があります。メニューが開いたままページの他の場所に移動してしまうことはありません。
リソース
COLRv1 フォント
COLRv1 フォント以前は、ウェブには OT-SVG フォントがありました。これは、グラデーション、組み込みの色と効果を備えたフォント用のオープン形式です。ただし、これらのファイルは非常に大きくなり、テキストの編集は可能でしたが、カスタマイズの範囲は限られていました。
COLRv1 フォントの後、ウェブはフットプリントが小さく、ベクター スケーラブルで再配置可能で、グラデーション機能とブレンドモードを活用したフォントが用意されており、ユースケースやブランドに合わせてフォントをカスタマイズするためのパラメータを使用できます。
以下に、絵文字に関する Chrome デベロッパー ブログ投稿の例を示します。絵文字のフォントサイズを大きくしても、鮮明さが保たれないことにお気づきかもしれません。ベクター アートではなく画像です。多くの場合、アプリで絵文字を使用する場合は、品質の高いアセットに置き換えられます。COLRv1 フォントを使用すると、絵文字はベクターで美しく表示されます。
アイコンフォントでは、この形式を使用して、カスタム デュオトーン カラーパレットなどを実現できます。COLRv1 フォントの読み込みは、他のフォント ファイルの場合と同様です。
@import url(https://fonts.googleapis.com/css2?family=Bungee+Spice);
COLRv1 フォントのカスタマイズは、@font-palette-values
で行われます。これは、後で参照できるように、カスタマイズ オプション セットをグループ化して名前を付けるための特別な CSS ルールです。カスタム プロパティと同じように、--
で始まるカスタム名を指定する点に注意してください。
@import url(https://fonts.googleapis.com/css2?family=Bungee+Spice);
@font-palette-values --colorized {
font-family: "Bungee Spice";
base-palette: 0;
override-colors: 0 hotpink, 1 cyan, 2 white;
}
カスタマイズのエイリアスとして --colorized
を使用した最後のステップは、カラー フォント ファミリーを使用している要素にパレットを適用することです。
@import url(https://fonts.googleapis.com/css2?family=Bungee+Spice);
@font-palette-values --colorized {
font-family: "Bungee Spice";
base-palette: 0;
override-colors: 0 hotpink, 1 cyan, 2 white;
}
.spicy {
font-family: "Bungee Spice";
font-palette: --colorized;
}
指定可能なフォントとカラーフォントがますます利用可能になり、ウェブ タイポグラフィは豊富なカスタマイズと創造的な表現に向かって大きく前進しています。
リソース
ビューポートの単位
新しいビューポートのバリエーションが登場する前は、ビューポートの適合をサポートする物理ユニットが提供されていました。高さ、幅、最小サイズ(vmin)、最大サイズ(vmax)の 4 つがありました。これらは多くの点でうまく機能しましたが、モバイル ブラウザでは複雑さが増していました。
モバイルでは、ページの読み込み時に URL を含むステータスバーが表示されます。このバーはビューポートの一部を占有します。数秒間操作が行われなかった場合や、ユーザーがシステムバー以外の部分でタップなどの操作を行った場合、システムバーは自動的に非表示になります。ただし、そのバーがスライドアウトすると、ビューポートの高さは変更され、vh
ユニットはターゲット サイズの変更に応じて移動してサイズ変更されます。後年、vh
ユニットは、モバイル デバイスで視覚的なレイアウトの問題を引き起こしていたため、2 つのビューポート サイズのどちらを使用するかを決定することが特に必要になりました。vh
は常に最大のビューポートを表すことが決定されました。
.original-viewport-units {
height: 100vh;
width: 100vw;
--size: 100vmin;
--size: 100vmax;
}
新しいビューポート バリアントが導入された後、小、大、動的のビューポート ユニットが利用可能になり、物理ビューポートに論理的な同等物が追加されます。デベロッパーとデザイナーが、特定のシナリオに使用する単位を選択できるようにすることを目的としています。ステータスバーが消えたときにレイアウトが少しずれるのは問題ないと思われる場合は、dvh
(動的ビューポートの高さ)を安心して使用できます。
新しいビューポート バリエーションによって利用可能になった新しいビューポート単位のオプションは次のとおりです。
.new-height-viewport-units { height: 100vh; height: 100dvh; height: 100svh; height: 100lvh; block-size: 100vb; block-size: 100dvb; block-size: 100svb; block-size: 100lvb; }
.new-width-viewport-units { width: 100vw; width: 100dvw; width: 100svw; width: 100lvw; inline-size: 100vi; inline-size: 100dvi; inline-size: 100svi; inline-size: 100lvi; }
.new-min-viewport-units { --size: 100vmin; --size: 100dvmin; --size: 100svmin; --size: 100lvmin; }
.new-max-viewport-units { --size: 100vmax; --size: 100dvmax; --size: 100svmax; --size: 100lvmax; }
これにより、デベロッパーやデザイナーがビューポートのレスポンシブ デザインを実現するために必要な柔軟性を得られることを願っています。
リソース
:has()
:has()
より前は、セレクタのサブジェクトは常に末尾にありました。たとえば、このセレクタのサブジェクトはリスト アイテム ul > li
です。疑似セレクタはセレクタを変更できますが、サブジェクト(ul > li:hover
または ul >
li:not(.selected)
)は変更しません。
:has()
の後で、要素ツリー内の上位の被写体は、子に関するクエリ(ul:has(> li)
)を提供しながら被写体として残ることができます。この場合、セレクタのサブジェクトが親になるため、:has()
が「親セレクタ」という一般名を取得した理由は簡単に理解できます。
クラス .parent
がサブジェクトのままで、子要素に .child
クラスが含まれている場合にのみ選択される基本的な構文の例を次に示します。
.parent:has(.child) {...}
<section>
要素がサブジェクトであるが、子の 1 つに :focus-visible
がある場合にのみセレクタが一致する例を次に示します。
section:has(*:focus-visible) {...}
より実用的なユースケースが明らかになると、:has()
セレクタは素晴らしいユーティリティになります。たとえば、現時点では、画像をラップする際に <a>
タグを選択することはできないため、アンカータグにそのユースケースでスタイルを変更する方法を教えることは困難です。ただし、:has()
では可能です。
a:has(> img) {...}
これらはすべて、:has()
が親セレクタのように見えるだけの例です。<figure>
要素内の画像を使用し、図に <figcaption>
がある場合は画像のスタイルを調整するユースケースについて考えてみましょう。次の例では、figcaption を含む図が選択され、そのコンテキスト内の画像が選択されます。:has()
が使用され、被写体は変更されません。ターゲットとする被写体は図ではなく画像であるためです。
figure:has(figcaption) img {...}
組み合わせは無限に存在します。:has()
を数量クエリと組み合わせて、子の数に基づいて CSS グリッド レイアウトを調整します。:has()
をインタラクティブな疑似クラス状態と組み合わせて、新しいクリエイティブな方法で応答するアプリを作成します。
サポートの確認は、@supports
とその selector()
関数を使用して簡単に行えます。この関数は、ブラウザが構文を理解しているかどうかをテストしてから使用します。
@supports (selector(:has(works))) {
/* safe to use :has() */
}
リソース
2022 年以降
2022 年にこれらの優れた機能がすべてリリースされた後も、まだ難しいことがいくつかあります。次のセクションでは、未解決の問題と、その解決に向けて積極的に開発されているソリューションについて説明します。これらのソリューションは、ブラウザでフラグを使用して指定または利用可能であっても、試験運用版です。
次のセクションでは、これらの問題の解決を求めている多くの企業のユーザーがいることを理解していただくことを目的としています。これらの解決策が 2023 年にリリースされるということではありません。
型が緩いカスタム プロパティ
CSS のカスタム プロパティは素晴らしいものです。名前付き変数内にさまざまなものを格納し、拡張、計算、共有などを行えます。実質的には柔軟性に優れているため、柔軟性の低いものがあると便利です。
box-shadow
が値にカスタム プロパティを使用するシナリオについて考えてみましょう。
box-shadow: var(--x) var(--y) var(--blur) var(--spread) var(--color);
いずれかのプロパティが、CSS で使用できない値(--x: red
など)に変更されるまで、すべて正常に動作します。ネストされた変数のいずれかが欠落しているか、無効な値型に設定されている場合、シャドウ全体が破棄されます。
ここで @property
が役に立ちます。--x
は型付きカスタム プロパティにできます。これにより、柔軟性は失われますが、定義された境界内で安全に使用できるようになります。
@property --x {
syntax: '<length>';
initial-value: 0px;
inherits: false;
}
これで、box-shadow
が var(--x)
を使用し、その後 --x: red
が試行されると、red
は <length>
ではないため無視されます。つまり、カスタム プロパティのいずれかに無効な値が指定されていても、シャドウは引き続き機能します。失敗するのではなく、0px
の initial-value
に戻ります。
アニメーション
型安全性に加えて、アニメーションの可能性も広がります。CSS 構文は柔軟性が高いため、グラデーションなどのアニメーション化は不可能です。型付き CSS プロパティは、過度に複雑な補間内でデベロッパーの意図をブラウザに伝えることができるため、ここでは @property
が役立ちます。基本的に、ブラウザが以前はアニメーション化できなかったスタイルの要素をアニメーション化できる程度に、可能性の範囲を制限します。
次のデモ例では、放射状のグラデーションをオーバーレイの一部に使用して、スポットライトのフォーカス効果を作成しています。JavaScript は、alt キーまたは option キーが押されたときにマウスの x と y を設定し、焦点サイズを 25% などの小さい値に変更して、マウスの位置にスポットライトのフォーカス サークルを作成します。
.focus-effect {
--focal-size: 100%;
--mouse-x: center;
--mouse-y: center;
mask-image: radial-gradient(
circle at var(--mouse-x) var(--mouse-y),
transparent 0%,
transparent var(--focal-size),
black 0%
);
}
ただし、グラデーションをアニメーション化することはできません。アニメーションの設定方法をブラウザが「単純に導出」するには、柔軟性が高すぎて複雑すぎます。ただし、@property
を使用すると、1 つのプロパティを個別に入力してアニメーション化できるため、ブラウザはインテントを簡単に理解できます。
このフォーカス効果を使用するビデオゲームでは、大きな円からピンホール円までの円が常にアニメーション化されます。このデモで @property
を使用して、ブラウザでグラデーション マスクをアニメーション化する方法を次に示します。
@property --focal-size {
syntax: '<length-percentage>';
initial-value: 100%;
inherits: false;
}
.focus-effect {
--focal-size: 100%;
--mouse-x: center;
--mouse-y: center;
mask-image: radial-gradient(
circle at var(--mouse-x) var(--mouse-y),
transparent 0%,
transparent var(--focal-size),
black 0%
);
transition: --focal-size .3s ease;
}
変更のサーフェス領域を 1 つのプロパティに減らし、値を入力してブラウザが長さをインテリジェントに補間できるようにしたため、ブラウザでグラデーションのサイズをアニメーション化できるようになりました。
@property
には他にも多くの機能がありますが、これらの小さな機能の有効化は大きな効果をもたらします。
リソース
min-width
または max-width
にありました
メディアクエリの範囲の前に、CSS メディアクエリは min-width
と max-width
を使用して、上限と下限の条件を明記します。たとえば、次のようになります。
@media (min-width: 320px) {
…
}
メディアクエリの範囲を追加すると、同じメディアクエリは次のようになります。
@media (width >= 320px) {
…
}
min-width
と max-width
の両方を使用する CSS メディアクエリは次のようになります。
@media (min-width: 320px) and (max-width: 1280px) {
…
}
メディアクエリの範囲を追加すると、同じメディアクエリは次のようになります。
@media (320px <= width <= 1280px) {
…
}
コーディングの経験に応じて、どちらか一方が他方よりもはるかに読みやすく見えるでしょう。仕様が追加されたことで、デベロッパーはどちらを使用するかを選択したり、同じ意味で使用したりできるようになります。
リソース
メディアクエリ変数なし
@custom-media
より前は、メディアクエリを何度も繰り返す必要がありました。または、プリプロセッサに依存して、ビルド時に静的変数に基づいて適切な出力を生成する必要がありました。
@custom-media
以降、CSS では、カスタム プロパティと同様に、メディアクエリのエイリアスと参照が可能になります。
名前を付けることは非常に重要です。目的と構文を一致させることで、共有やチームでの使用が容易になります。プロジェクト間で私をフォローするカスタム メディア クエリをいくつか紹介します。
@custom-media --OSdark (prefers-color-scheme: dark);
@custom-media --OSlight (prefers-color-scheme: light);
@custom-media --pointer (hover) and (pointer: coarse);
@custom-media --mouse (hover) and (pointer: fine);
@custom-media --xxs-and-above (width >= 240px);
@custom-media --xxs-and-below (width <= 240px);
定義が完了したので、次のようにいずれかを使用できます。
@media (--OSdark) {
:root {
…
}
}
CSS カスタム プロパティ ライブラリ Open Props で使用しているカスタム メディア クエリの一覧をご覧ください。
リソース
セレクタのネストはとても便利
@nest
の登場前は、スタイルシートに多くの繰り返しがありました。セレクタが長く、それぞれが小さな違いをターゲットとしている場合は特に扱いづらくなりました。プリプロセッサを採用する理由の 1 つは、ネストの便利さです。
@nest
以降は繰り返しは行われません。プリプロセッサ対応のネストのほぼすべての機能が、CSS に組み込まれて利用可能になります。
article {
color: darkgray;
}
article > a {
color: var(--link-color);
}
/* with @nest becomes */
article {
color: darkgray;
& > a {
color: var(--link-color);
}
}
ネストの最も重要な点は、ネストされたセレクタで article
を繰り返さないことに加えて、スタイル設定のコンテキストが 1 つのスタイル ブロック内に保持されることです。1 つのセレクタとそのスタイルから、スタイルを持つ別のセレクタに移動するのではなく(例 1)、読者は記事のコンテキスト内にとどまり、記事内のリンクを確認できます。関係とスタイルのインテントがバンドルされているため、article
は独自のスタイルを所有しているように表示されます。
所有権は一元化と考えることもできます。関連するスタイルをスタイルシートで探すのではなく、それらすべてをコンテキスト内でネストして探すことができます。これは、親から子への関係だけでなく、子から親への関係でも機能します。
親がスタイルを所有して子を変更するのではなく、異なる親コンテキストで自身を調整するコンポーネントの子について考えてみましょう。
/* parent owns this, adjusting children */
section:focus-within > article {
border: 1px solid hotpink;
}
/* with @nest becomes */
/* article owns this, adjusting itself when inside a section:focus-within */
article {
@nest section:focus-within > & {
border: 1px solid hotpink;
}
}
@nest
は、より健全なスタイルの組織化、一元化、所有権の確保に役立ちます。コンポーネントは、他のスタイル ブロックに分散するのではなく、独自のスタイルをグループ化して所有できます。これらの例では小さく見えるかもしれませんが、利便性と読みやすさの両面で非常に大きな影響を与える可能性があります。
リソース
スタイルのスコーピングは非常に難しい
@scope
より前は、CSS のスタイルはデフォルトでカスケード、継承、グローバル スコープが設定されているため、多くの戦略がありました。CSS のこれらの機能は多くの場面で非常に便利ですが、さまざまなスタイルのコンポーネントが存在する複雑なサイトやアプリケーションでは、グローバル空間とカスケードの性質により、スタイルが漏れているように感じることがあります。
@scope
以降では、スタイルをクラスなどのコンテキスト内に限定するだけでなく、スタイルが終了し、カスケードや継承が続行されない場所を明示することもできます。
次の例では、BEM 命名規則のスコーピングを実際の意図に逆戻りできます。BEM セレクタは、header
要素の色のスコープを、命名規則を持つ .card
コンテナにしようとしています。これには、ヘッダーにこのクラス名が含まれていることが必要で、目標が達成されます。@scope
を使用すると、ヘッダー要素をマークアップせずに同じ目標を達成するために、命名規則は必要ありません。
.card__header {
color: var(--text);
}
/* with @scope becomes */
@scope (.card) {
header {
color: var(--text);
}
}
コンポーネント固有ではなく、CSS のグローバル スコープの性質に関する別の例を次に示します。ダークモードとライトモードはスタイルシート内で共存する必要があります。この場合、優先されるスタイルを決定する際に順序が重要になります。通常、これはダークモードのスタイルがライトモードのスタイルの後に続くことを意味します。これにより、ライトモードがデフォルトのスタイル、ダークモードがオプションのスタイルになります。@scope
で並べ替えとスコープの競合を回避します。
@scope (.light-theme) {
a { color: purple; }
}
@scope (.dark-theme) {
a { color: plum; }
}
@scope
を使用すると、スタイル スコープの終了位置を設定することもできます。これは、命名規則やプリプロセッサでは指定できません。これは特別なものであり、ブラウザに組み込まれている CSS でのみ実行できます。次の例では、.media-block
の子が .content
の兄弟または親である場合に、img
と .content
のスタイルのみを適用します。
@scope (.media-block) to (.content) {
img {
border-radius: 50%;
}
.content {
padding: 1em;
}
}
リソース
マサリ レイアウトの CSS 方法がない
グリッドを使用した CSS マサリが登場する前は、列または Flexbox を使用した CSS メソッドではコンテンツの順序が正確に表現されないため、JavaScript がマサリ レイアウトを実現する最良の方法でした。
グリッドを使用した CSS メイソンリーの後は、JavaScript ライブラリは不要になり、コンテンツの順序が正しくなります。
上記のデモは、次の CSS で実現できます。
.container {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: masonry;
}
レイアウト戦略が欠けていると認識され、安心感を与えます。Firefox で今すぐお試しください。
リソース
CSS はユーザーのデータ削減に役立たない
prefers-reduced-data
メディアクエリが導入される前は、JavaScript とサーバーはユーザーのオペレーティング システムまたはブラウザの「データセーバー」オプションに基づいて動作を変更できましたが、CSS は動作を変更できませんでした。
prefers-reduced-data
メディアクエリの後、CSS はユーザー エクスペリエンスの向上に参加し、データの保存に役立ちます。
@media (prefers-reduced-data: reduce) {
picture, video {
display: none;
}
}
上記の CSS はこのメディア スクロール コンポーネントで使用されており、大幅な節約が可能です。訪問者のビューポートのサイズが大きいほど、ページ読み込み時の節約効果は大きくなります。ユーザーがメディア スクロールバーを操作すると、保存は続行されます。すべての画像に loading="lazy"
属性が設定されており、CSS で要素が完全に非表示になっているため、画像のネットワーク リクエストは行われません。
私のテストでは、中程度のサイズのビューポートで、40 件のリクエストと 700 KB のリソースが最初に読み込まれました。ユーザーがメディア選択をスクロールすると、さらに多くのリクエストとリソースが読み込まれます。CSS と削減されたデータのメディアクエリを使用すると、10 件のリクエストと 172 KB のリソースが読み込まれます。これは 0.5 MB の節約に相当します。ユーザーがメディアをスクロールしたことがなく、その時点で追加のリクエストはありません。
データ量を削減するメリットは、データの節約だけではありません。表示されるタイトルが増え、注意をそらすカバー画像がないため、多くのユーザーは、データ通信量に応じて料金が請求されるため、データ セーバー モードでブラウジングしています。CSS がここで役立つと、本当に助かります。
リソース
- prefers-reduced-data の指定
- MDN の prefers-reduced-data
- Prefers-reduced-data を GUI チャレンジで
- Smashing Magazine: Maximize Core Web Vitals、A Smashing Magazine ケーススタディ
スクロール スナップ機能の制限が多すぎる
これらのスクロール スナップ案が提案される前は、カルーセル、スライダー、ギャラリーを管理するために独自の JavaScript を記述すると、すべてのオブザーバーと状態管理によってすぐに複雑になる可能性があります。また、注意しないと、自然なスクロール速度がスクリプトによって正規化され、ユーザー操作が少し不自然で、操作しづらくなる可能性があります。
新しい API
snapChanging()
ブラウザが Snap の子を解放するとすぐに、このイベントが発生します。これにより、UI はスナップ チルドの欠如とスクロールバーの未確定のスナップ状態を反映できます。これは、スクロールバーが使用され、新しい場所に移動するためです。
document.querySelector('.snap-carousel').addEventListener('snapchanging', event => {
console.log('Snap is changing', event.snappedTargetsList);
});
snapChanged()
ブラウザが新しい子にスナップし、スクローラーが停止するとすぐにこのイベントが発生します。これにより、スナップされた子に依存するすべての UI を更新して接続を反映できます。
document.querySelector('.snap-carousel').addEventListener('snapchanged', event => {
console.log('Snap changed', event.snappedTargetsList);
});
scroll-start
スクロールは必ずしも最初から始まるわけではありません。左または右にスワイプすると異なるイベントがトリガーされるスワイプ可能なコンポーネントや、ページの読み込み時に最初は隠れていて、上までスクロールすると表示される検索バーなどを検討してください。この CSS プロパティを使用すると、スクロールを特定の位置から開始するように指定できます。
:root { --nav-height: 100px }
.snap-scroll-y {
scroll-start-y: var(--nav-height);
}
:snap-target
この CSS セレクタは、現在ブラウザによってスナップされているスクロール スナップ コンテナ内の要素と一致します。
.card {
--shadow-distance: 5px;
box-shadow: 0 var(--shadow-distance) 5px hsl(0 0% 0% / 25%);
transition: box-shadow 350ms ease;
}
.card:snapped {
--shadow-distance: 30px;
}
これらのスクロール スナップ案により、ブラウザでこのタスクが容易になり、オブザーバーとスクロール オーケストレーション コードが不要になり、組み込み API を使用できるようになりました。これにより、スライダー、カルーセル、ギャラリーの作成が大幅に容易になります。
これらの CSS と JS の機能はまだ初期段階ですが、これらの機能の導入とテストに役立つポリフィルがまもなく提供される予定です。
リソース
既知の状態を循環する
toggle()
より前は、スタイル設定とインタラクションに利用できる状態は、ブラウザに組み込まれている状態のみでした。たとえば、チェックボックス入力には :checked
があります。これは、CSS が要素を視覚的に変更するために使用できる、入力の内部管理ブラウザ状態です。
toggle()
の後、任意の要素にカスタム ステータスを作成して、CSS で変更してスタイル設定に使用できます。グループ化、切り替え、指向性切り替えなどを行えます。
次の例では、チェックボックス要素を使用せずに、完了したリストアイテムの取り消し線と同じ効果が得られます。
<ul class='ingredients'>
<li>1 banana
<li>1 cup blueberries
...
</ul>
関連する CSS toggle()
スタイルは次のとおりです。
li {
toggle-root: check self;
}
li:toggle(check) {
text-decoration: line-through;
}
状態マシンに精通している場合は、toggle()
とのクロスオーバーが非常に多いことに気付くでしょう。この機能により、デベロッパーは CSS に状態をより多く組み込むことができるため、インタラクションと状態をより明確でセマンティックな方法でオーケストレートできるようになります。
リソース
選択要素のカスタマイズ
<selectmenu>
より前は、CSS でリッチ HTML を使用して <option>
要素をカスタマイズしたり、オプション リストの表示を大幅に変更したりすることはできませんでした。そのため、開発者は <select>
の機能の多くを再現する外部ライブラリを読み込む必要があり、結果として多くの作業が必要になりました。
<selectmenu>
以降、デベロッパーは、ユーザー補助要件を満たし、セマンティック HTML を提供しながら、オプション要素にリッチな HTML を提供し、必要に応じてスタイルを設定できます。
次の例では、<selectmenu>
説明ページから、いくつかの基本的なオプションを含む新しい選択メニューを作成しています。
<selectmenu>
<option>Option 1</option>
<option>Option 2</option>
<option>Option 3</option>
</selectmenu>
CSS では、要素の各部分をターゲットに設定してスタイルを設定できます。
.my-select-menu::part(button) {
color: white;
background-color: red;
padding: 5px;
border-radius: 5px;
}
.my-select-menu::part(listbox) {
padding: 10px;
margin-top: 5px;
border: 1px solid red;
border-radius: 5px;
}
ウェブ試験運用版フラグを有効にして、Canary 版 Chromium で <selectmenu>
要素を試すことができます。2023 年以降は、カスタマイズ可能な選択メニュー要素に注意してください。
リソース
要素を別の要素にアンカーする
anchor()
より前は、デベロッパーが親要素内で子要素を移動できるように、絶対位置と相対位置の位置戦略が用意されていました。
anchor()
以降、デベロッパーは、子要素かどうかにかかわらず、要素を他の要素に配置できます。また、デベロッパーは、配置するエッジを指定したり、要素間の位置関係を作成するためのその他の細かい設定を行ったりすることもできます。
詳細については、説明に記載されているいくつかの例とコードサンプルをご覧ください。