CSS 2022 の現状

Google IO 2022 で発表された、現在と将来のウェブ スタイリング機能と、その他の機能。

2022 年は、CSS の機能とブラウザの共同機能リリースにおいて、CSS にとって最も重要な年の一つとなるでしょう。14 個の機能を実装するという共同目標を掲げています。

概要

この記事は、Google IO 2022 で行われた講演を記事形式にしたものです。各機能の詳細なガイドではなく、興味を引くための概要と簡単な紹介を目的としており、深さよりも幅広さを重視しています。興味をお持ちになった場合は、セクションの最後に記載されているリソースへのリンクで詳細をご確認ください。

目次

以下のリストから、関心のあるトピックに移動できます。

ブラウザの互換性

これほど多くの CSS 機能が協調リリースに設定されている主な理由は、Interop 2022 の取り組みによるものです。Interop の取り組みを学ぶ前に、Compat 2021 の取り組みを見ておくことが重要です。

Compat 2021

2021 年の目標は、アンケートを通じてデベロッパーから寄せられたフィードバックに基づき、現在の機能を安定させ、テストスイートを改善し、5 つの機能についてブラウザの合格スコアを向上させることでした。

  1. sticky のポジショニング
  2. aspect-ratio のサイズ設定
  3. レイアウト: flex
  4. レイアウト: grid
  5. transform の位置とアニメーション

テストスコアが全体的に向上し、安定性と信頼性が向上しました。チームの皆様、おめでとうございます。

Interop 2022

今年は、ブラウザが協力して、取り組む予定の機能と優先順位について話し合い、取り組みを統合しました。デベロッパー向けに次のウェブ機能をリリースする予定でした。

  1. @layer
  2. 色空間と関数
  3. 封じ込め
  4. <dialog>
  5. フォームの互換性
  6. スクロール
  7. サブグリッド
  8. タイポグラフィ
  9. ビューポート単位
  10. ウェブ互換性

このリストは、ワクワクするような野心的なリストであり、その展開が楽しみです。

2022 年の最新情報

当然のことながら、CSS 2022 の状況は Interop 2022 の作業に大きく影響されています。

カスケード レイヤ

Browser Support

  • Chrome: 99.
  • Edge: 99.
  • Firefox: 97.
  • Safari: 15.4.

Source

@layer 以前は、読み込まれたスタイルシートの検出順序が非常に重要でした。最後に読み込まれたスタイルは、以前に読み込まれたスタイルを上書きできるためです。これにより、エントリ スタイルシートが細かく管理され、重要度の低いスタイルを先に読み込み、重要度の高いスタイルを後で読み込む必要がありました。この重要性をデベロッパーが管理できるように、ITCSS などの方法論が存在します。

@layer を使用すると、エントリ ファイルでレイヤとその順序を事前に定義できます。その後、スタイルが読み込まれるか、読み込まれるか、定義されると、レイヤ内に配置できます。これにより、スタイルのオーバーライドの重要性を維持できますが、読み込みオーケストレーションを細かく管理する必要はありません。

この動画では、定義されたカスケード レイヤにより、必要に応じてカスケードを維持しながら、より自由でフリースタイルの作成と読み込みのプロセスが可能になる様子を示しています。

Chrome DevTools は、どのスタイルがどのレイヤから来ているかを視覚化するのに役立ちます。

Chrome DevTools の [スタイル] サイドバーのスクリーンショット。新しいレイヤ グループ内にスタイルが表示される様子がハイライト表示されています。

リソース

サブグリッド

Browser Support

  • Chrome: 117.
  • Edge: 117.
  • Firefox: 71.
  • Safari: 16.

Source

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 のみ)。次の図では、親グリッドとサブグリッドが重ねられています。これで、デザイナーが考えていたレイアウトに近づきました。

Chrome Devtools のグリッド オーバーレイ ツールを使用して、CSS で定義された線を表示しているサブグリッド デモのスクリーンショット。

デベロッパー ツールの要素パネルで、どの要素がグリッドとサブグリッドであるかを確認できます。これは、レイアウトのデバッグや検証に非常に役立ちます。

Chrome デベロッパー ツールの [Elements] パネルのスクリーンショット。どの要素にグリッド レイアウトまたはサブグリッド レイアウトが適用されているかがラベル付けされています。
Firefox Devtools のスクリーンショット

リソース

コンテナクエリ

Browser Support

  • Chrome: 105.
  • Edge: 105.
  • Firefox: 110.
  • Safari: 16.

Source

@container 以前は、ウェブページの要素はビューポート全体のサイズにしか対応できませんでした。これはマクロ レイアウトには適していますが、マイクロ レイアウトでは、外側のコンテナがビューポート全体ではないため、レイアウトをそれに応じて調整することはできません。

@container の後、要素は親コンテナのサイズやスタイルに応答できるようになります。唯一の注意点は、コンテナがクエリのターゲットとして宣言する必要があることです。これは、大きなメリットを得るための小さな要件です。

/* establish a container */
.day {
  container-type: inline-size;
  container-name: calendar-day;
}

これらのスタイルにより、次の動画の月曜日、火曜日、水曜日、木曜日、金曜日の列をイベント要素でクエリできるようになります。

デモUna Kravets 著)

calendar-day コンテナのサイズをクエリし、レイアウトとフォントサイズを調整する CSS は次のとおりです。

@container calendar-day (max-width: 200px) {
  .date {
    display: block;
  }

  .date-num {
    font-size: 2.5rem;
    display: block;
  }
}

別の例として、書籍コンポーネントがドラッグ先の列の空きスペースに合わせて調整される様子を次に示します。

デモ 作成者: Max Böck

Una の「新しいレスポンシブ」という状況の評価は正しいです。@container を使用する際には、多くのエキサイティングで有意義な設計上の決定を行う必要があります。

リソース

accent-color

Browser Support

  • Chrome: 93.
  • Edge: 93.
  • Firefox: 92.
  • Safari: 15.4.

Source

accent-color 以前は、ブランドに合った色を使用したフォームが必要な場合、複雑なライブラリや CSS ソリューションを使用することになり、時間の経過とともに管理が難しくなることがありました。すべてのオプションが提供され、アクセシビリティも含まれていることを期待しますが、組み込みコンポーネントを使用するか、独自のコンポーネントを採用するかを毎回選択するのは面倒です。

accent-color の後、1 行の CSS でブランドカラーを組み込みコンポーネントに適用します。ブラウザは、色合いに加えて、コンポーネントの補助部分に適切なコントラスト カラーをインテリジェントに選択し、システム カラー スキーム(ライトまたはダーク)に適応します。

/* tint everything */
:root {
  accent-color: hotpink;
}

/* tint one element */
progress {
  accent-color: indigo;
}

ライトモードとダークモードのアクセント付き HTML 要素を並べて比較した画像。

accent-color の詳細については、web.dev の投稿をご覧ください。この便利な 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()

Browser Support

  • Chrome: 101.
  • Edge: 101.
  • Firefox: 96.
  • Safari: 15.

Source

HWB は、色相(Hue)、白さ(Whiteness)、黒さ(Blackness)の略です。色相と、明るくしたり暗くしたりするための白または黒の量だけなので、人間が理解しやすい方法で色を表現できます。白や黒を混ぜて色を作成するアーティストは、この色の構文の追加を気に入るかもしれません。

このカラー関数を使用すると、HSL や RGB と同じように、sRGB 色空間の色が生成されます。2022 年の新機能という点では、新しい色はありませんが、構文とメンタルモデルのファンにとっては、一部のタスクが簡単になる可能性があります。

リソース

色空間

色の表現は色空間で行われます。各カラースペースには、色を扱うためのさまざまな機能とトレードオフがあります。明るい色をすべてまとめて配置する人もいれば、明るさに基づいて並べてから配置する人もいます。

2022 CSS では、10 個の新しいカラースペースが提供される予定です。それぞれに独自の機能があり、デザイナーやデベロッパーが色を表示、選択、混合する際に役立ちます。以前は、色を扱うための唯一のオプションは sRGB でしたが、CSS によって新しい可能性と新しいデフォルトの色空間である LCH が実現しました。

color-mix()

Browser Support

  • Chrome: 111.
  • Edge: 111.
  • Firefox: 113.
  • Safari: 16.2.

Source

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() 以前は、スタイルシートの作成者はアクセシブルな色を事前に知っておく必要がありました。多くの場合、パレットにはカラー見本に黒または白のテキストが表示され、カラー システムのユーザーに、その見本と適切にコントラストをなすために必要なテキストの色が示されます。

14 色と、テキストに適した白または黒のコントラスト カラーが表示された 3 つのマテリアル パレットのスクリーンショット。
2014 マテリアル デザインのカラーパレットの例

color-contrast() の後、スタイルシートの作成者はタスクをブラウザに完全にオフロードできます。ブラウザを使用して黒または白の色を自動的に選択できるだけでなく、デザイン システムに適した色のリストを指定して、目的のコントラスト比率を満たす最初の色を選択することもできます。

次のスクリーンショットは、見本の色に基づいてブラウザがテキストの色を自動的に選択する HWB カラーパレット セットのデモです。

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 言語自体に組み込まれれば、アクセシブルで読みやすいインターフェースをどれほど簡単に提供できるようになるか考えてみてください。

リソース

相対色の構文

Browser Support

  • Chrome: 111.
  • Edge: 111.
  • Firefox: 113.
  • Safari: 15.

Source

相対色構文を使用する前は、色を計算して調整するために、色チャンネルを個別にカスタム プロパティに配置する必要がありました。この制限により、HSL は色を操作するためのプライマリ カラー関数にもなりました。これは、色相、彩度、明度を calc() で簡単に調整できるためです。

相対色構文を使用すると、任意の空間の任意の色を分解、変更して、色として返すことができます。これらすべてを 1 行の CSS で行えます。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() を使用してラベルのコントラストが適切になるようにしています。

3 列のスクリーンショット。各列は中央の列よりも暗いか明るい。
デモを試す

この関数は、カラーパレットの生成にも使用できます。提供されたベースカラーからパレット全体を生成するデモを以下に示します。この 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);
}
CSS によって動的に生成された 15 個のパレットのスクリーンショット。
デモを試す

ここまでで、色空間とさまざまな色関数が、それぞれの長所と短所に基づいて、さまざまな目的に使用できることがおわかりいただけたかと思います。

リソース

グラデーションの色空間

グラデーション色空間が導入される前は、デフォルトの色空間として sRGB が使用されていました。sRGB は一般的に信頼性が高いですが、グレーのデッドゾーンなどの弱点があります。

グリッド内の 4 つのグラデーション。すべてシアンからディープピンクに変化しています。LCH と LAB は彩度がより一貫していますが、sRGB は中間で少し彩度が下がります。

グラデーションの色空間の後に、色の補間に使用する色空間をブラウザに伝えます。これにより、デベロッパーとデザイナーは好みのグラデーションを選択できます。デフォルトの色空間も sRGB ではなく LCH に変更されます。

構文の追加はグラデーションの方向の後に行われ、新しい in 構文を使用します。これは省略可能です。

background-image: linear-gradient(
  to right in hsl,
  black, white
);

background-image: linear-gradient(
  to right in lch,
  black, white
);

黒から白への基本的なグラデーションです。各色空間の結果の範囲を確認します。黒に達するタイミングが早すぎたり、白にフェードアウトするタイミングが遅すぎたりする場合があります。

黒と白を比較した 11 個の色空間が表示されています。

次の例では、黒はグラデーションの既知の問題空間であるため、青に移行されます。ほとんどの色空間では、色の補間中に紫が混入します。これは、色空間内で色が点 A から点 B に移動する際に発生します。グラデーションは点 A から点 B までの直線をたどるため、色空間の形状によって、パスがたどる途中のストップが大きく変化します。

青と黒を比較した 11 個の色空間が表示されています。

詳細な説明、例、コメントについては、こちらの Twitter スレッドをご覧ください。

リソース

inert

Browser Support

  • Chrome: 102.
  • Edge: 102.
  • Firefox: 112.
  • Safari: 15.5.

Source

inert 以前は、ユーザーの注意をすぐに必要なページやアプリの領域に誘導することが推奨されていました。このガイド付きフォーカス戦略は、フォーカス トラップと呼ばれるようになりました。これは、デベロッパーがフォーカスをインタラクティブなスペースに配置し、フォーカス変更イベントをリッスンし、フォーカスがインタラクティブなスペースから離れた場合に、強制的に戻すためです。キーボードまたはスクリーン リーダーを使用しているユーザーは、タスクが完了してから次に進むように、インタラクティブ スペースに戻るよう指示されます。

inert の後は、ページやアプリのセクション全体をフリーズまたはガードできるため、トラップは必要ありません。ドキュメントのそれらの部分が不活性な間は、クリックやフォーカス変更の試みは単に利用できません。これは、罠ではなくガードのようなものと考えることもできます。inert は、ユーザーをどこかに留まらせるのではなく、他の場所を利用できないようにします。

この良い例として、JavaScript の alert() 関数があります。

ウェブサイトがインタラクティブとして表示され、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 はスライドアウト サイドメニューのユーザー エクスペリエンスなどにも役立ちます。ユーザーがサイドメニューをスライドして開いたときに、マウスやキーボードで背後のページを操作できるようにするのはよくありません。ユーザーにとって少しややこしくなります。代わりに、サイドメニューが表示されているときはページを inert にし、ユーザーがサイドメニューを閉じるか、サイドメニュー内で移動する必要があるようにします。これにより、メニューが開いた状態でページ内の別の場所に迷い込むことはなくなります。

リソース

COLRv1 フォント

COLRv1 フォント以前は、グラデーションや組み込みの色と効果を備えたフォントのオープン形式である OT-SVG フォントがウェブに存在していました。ただし、これらのテキストは非常に大きくなる可能性があり、テキストの編集はできても、カスタマイズの余地はあまりありませんでした。

COLRv1 フォントの登場により、ウェブではフットプリントが小さく、ベクトル スケーラブルで、再配置可能で、グラデーションを特徴とし、ブレンドモードを搭載したフォントが利用できるようになりました。これらのフォントは、ユースケースごとにフォントをカスタマイズしたり、ブランドに合わせてフォントを調整したりするためのパラメータを受け取ります。

COLRv1 フォントがより鮮明で小さいことを示す比較の可視化と棒グラフ。
画像引用元: https://developer.chrome.com/blog/colrv1-fonts/

以下は、絵文字に関する Chrome デベロッパー ブログ投稿の例です。絵文字のフォントサイズを大きくすると、鮮明さが失われることに気づいた方もいるかもしれません。ベクター アートではなく画像です。多くの場合、アプリで絵文字が使用されると、より高品質なアセットに置き換えられます。COLRv1 フォントでは、絵文字はベクターで美しく表示されます。

アイコン フォントでは、この形式を使用して、カスタムのデュオトーン カラーパレットなどを提供できます。COLRv1 フォントの読み込みは、他のフォント ファイルと同様です。

@import url(https://fonts.googleapis.com/css2?family=Bungee+Spice);

COLRv1 フォントのカスタマイズは、@font-palette-values を使用して行います。これは、カスタマイズ オプションのセットをバンドルにグループ化して名前を付け、後で参照できるようにするための特別な CSS at-rule です。カスタム プロパティと同様に、-- で始まるカスタム名を指定する方法に注目してください。

@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;
}
「DUNE」という単語が Bungee Spice フォントで表示されているスクリーンショット。
カスタムカラーで表示された Bungee Spice フォント。ソースは https://developer.chrome.com/blog/colrv1-fonts/

バリアブル フォントやカラー フォントがますます利用可能になるにつれて、ウェブ タイポグラフィは、豊富なカスタマイズとクリエイティブな表現に向けて非常に素晴らしい道を歩んでいます。

リソース

ビューポート単位

デバイスの画面、ブラウザ ウィンドウ、iframe のビューポートがそれぞれ異なることを示す図。

新しいビューポート バリエーションが登場する前は、ウェブでビューポートの調整を支援する物理単位が提供されていました。高さ、幅、最小サイズ(vmin)、最大サイズ(vmax)の 4 つがありました。この方法は多くの点で有効でしたが、モバイル ブラウザの登場により複雑さが増しました。

モバイルでページを読み込むと、URL が表示されたステータスバーが表示され、このバーがビューポートのスペースの一部を占有します。数秒後、ユーザーが操作を行うと、ステータスバーがスライドして非表示になり、ユーザーがより大きなビューポートで操作できるようになります。しかし、そのバーがスライドアウトすると、ビューポートの高さが変わり、vh 単位はターゲット サイズが変わるにつれてシフトし、サイズ変更されます。その後、モバイル デバイスでレイアウトの視覚的な問題が発生したため、vh 単位は 2 つのビューポート サイズのどちらを使用するかを明確に決定する必要がありました。vh は常に最大のビューポートを表すことが決定されました。

.original-viewport-units {
  height: 100vh;
  width: 100vw;
  --size: 100vmin;
  --size: 100vmax;
}

新しいビューポート バリエーション(小、大、動的ビューポート単位)が利用可能になり、物理単位に論理同等物が追加されます。このアイデアは、デベロッパーとデザイナーが特定のシナリオで使用する単位を選択できるようにすることを目的としています。ステータスバーが消えるときにレイアウト シフトが少し発生しても問題ないかもしれません。その場合は、dvh(動的ビューポートの高さ)を安心して使用できます。

DVH、LVH、SVH を説明する 3 台のスマートフォンのイラスト。DVH の例のスマートフォンには 2 本の縦線があります。1 本は検索バーの下部とビューポートの下部の間、もう 1 本は検索バーの上部(システム ステータスバーの下)とビューポートの下部の間です。これは、DVH がこの 2 つの長さのいずれかになることを示しています。LVH は中央に表示され、デバイスのステータスバーの下部とスマートフォンのビューポートのボタンの間に 1 行のスペースがあります。最後は SVH 単位の例で、ブラウザの検索バーの下端からビューポートの下端までの線を示しています。

新しいビューポート バリエーションで利用可能になった新しいビューポート単位オプションの完全なリストは次のとおりです。

高さのビューポート単位
​​.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()

Browser Support

  • Chrome: 105.
  • Edge: 105.
  • Firefox: 121.
  • Safari: 15.4.

Source

:has() より前は、セレクタサブジェクトは常に末尾にありました。たとえば、このセレクタのサブジェクトはリスト アイテム ul > li です。疑似セレクタはセレクタを変更できますが、サブジェクト(ul > li:hover または ul > li:not(.selected))は変更しません。

:has() の後、要素ツリーの上位にあるサブジェクトは、子に関するクエリ(ul:has(> li))を提供しながら、サブジェクトのままでいることができます。セレクタの対象が親になるため、:has() が「親セレクタ」という一般的な名前になった理由が簡単に理解できます。

クラス .parent が対象のままで、子要素に .child クラスがある場合にのみ選択される基本的な構文の例を次に示します。

.parent:has(.child) {...}

次の例では、<section> 要素がサブジェクトですが、セレクタは子要素のいずれかに :focus-visible がある場合にのみ一致します。

section:has(*:focus-visible) {...}

:has() セレクタは、より実用的なユースケースが明らかになると、再び優れたユーティリティになります。たとえば、現在、<a> タグが画像をラップしている場合、そのタグを選択することはできません。そのため、アンカータグがそのユースケースでスタイルを変更する方法を教えることが困難になっています。ただし、:has() を使用すれば可能です。

a:has(> img) {...}

これまでは、:has() が親セレクタのように見える例ばかりでした。<figure> 要素内の画像の使用例と、図に <figcaption> がある場合の画像のスタイルの調整について検討します。次の例では、図と図のキャプションが選択され、そのコンテキスト内の画像が選択されます。:has() が使用され、対象は画像であり図ではないため、サブジェクトは変更されません。

figure:has(figcaption) img {...}

組み合わせは無限にあります。:has()数量クエリと組み合わせて、子の数に基づいて CSS グリッド レイアウトを調整します。:has()インタラクティブな疑似クラスの状態を組み合わせて、新しいクリエイティブな方法で応答するアプリケーションを作成します。

@supports とその selector() 関数を使用すると、サポートの確認が簡単になります。この関数は、構文を使用する前にブラウザが構文を理解しているかどうかをテストします。

@supports (selector(:has(works))) {
  /* safe to use :has() */
}

リソース

2022 年以降

2022 年にこれらのすばらしい機能がリリースされた後も、難しいことがいくつかあります。次のセクションでは、残りの問題と、それらを解決するために積極的に開発されているソリューションについて説明します。これらのソリューションは、ブラウザのフラグの背後で指定または利用可能であっても、試験運用版です。

次のセクションの要点は、これらの問題の解決策を多くの企業が求めているという安心感を得ることです。これらの解決策が 2023 年にリリースされるということではありません。

型指定のないカスタム プロパティ

Browser Support

  • Chrome: 85.
  • Edge: 85.
  • Firefox: 128.
  • Safari: 16.4.

Source

CSS のカスタム プロパティは素晴らしいです。名前付き変数内にあらゆるものを格納し、拡張、計算、共有などを行うことができます。実際、柔軟性が高すぎるため、柔軟性が低いものもあればいいなと思います。

box-shadow が値にカスタム プロパティを使用するシナリオについて考えてみましょう。

box-shadow: var(--x) var(--y) var(--blur) var(--spread) var(--color);

この方法は、プロパティのいずれかが --x: red など、CSS が受け付けない値に変更されるまでは有効です。ネストされた変数のいずれかが欠落しているか、無効な値の型に設定されている場合、シャドウ全体が破損します。

ここで @property が登場します。--x は型付きのカスタム プロパティになり、緩やかで柔軟なものではなくなり、定義された境界線を持つ安全なものになります。

@property --x {
  syntax: '<length>';
  initial-value: 0px;
  inherits: false;
}

box-shadowvar(--x) を使用し、その後 --x: red が試行されると、red<length> ではないため無視されます。つまり、カスタム プロパティの 1 つに無効な値が指定されていても、シャドウは引き続き機能します。失敗する代わりに、0pxinitial-value に戻ります。

アニメーション

型安全性のほか、アニメーションの可能性も広がります。CSS 構文の柔軟性により、グラデーションなど、アニメーション化できないものもあります。@property は、型付き CSS プロパティが、複雑すぎる補間の中でデベロッパーの意図をブラウザに伝えることができるため、ここで役立ちます。これにより、ブラウザが以前はアニメーション化できなかったスタイルの側面をアニメーション化できるようになり、可能性の範囲が大幅に広がります。

このデモの例では、放射グラデーションを使用してオーバーレイの一部を作成し、スポットライト フォーカス効果を生み出しています。JavaScript は、alt キーまたは opt キーが押されたときにマウスの 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-widthmax-width を使用して、条件の上限と下限を明確にします。たとえば、次のようになります。

@media (min-width: 320px) {
  
}

メディアクエリの範囲を使用すると、同じメディアクエリは次のようになります。

@media (width >= 320px) {
  
}

min-widthmax-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)のではなく、読者は記事のコンテキスト内に留まり、記事内のリンクを確認できます。関係とスタイルのインテントはバンドルされているため、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 は、スタイル全体の整理、一元化、所有権の健全性を高めるのに役立ちます。コンポーネントは、他のスタイル ブロックに分散させるのではなく、独自のスタイルをグループ化して所有できます。これらの例では小さな変更に見えるかもしれませんが、利便性と可読性の両面で大きな影響を与える可能性があります。

リソース

スタイルのスコープ設定は非常に難しい

Browser Support

  • Chrome: 118.
  • Edge: 118.
  • Firefox: behind a flag.
  • Safari: 17.4.

Source

@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 での Masonry レイアウトの方法はありません

グリッドを使用した CSS の masonry レイアウトが登場するまでは、JavaScript が masonry レイアウトを実現する最良の方法でした。列や flexbox を使用した CSS の方法では、コンテンツの順序が正確に表現されなかったためです。

CSS グリッドによる CSS メイソンリーの導入後は、JavaScript ライブラリは不要になり、コンテンツの順序も正しくなります。

上から下へ移動する数字が表示された、レンガ積みレイアウトのスクリーンショット。
Smashing Magazine の画像とデモ
https://www.smashingmagazine.com/native-css-masonry-layout-css-grid/

上記のデモは、次の CSS で実現されています。

.container {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: masonry;
}

このレイアウト戦略が欠落していることが認識されていることは安心できます。また、Firefox で今すぐ試すこともできます。

リソース

CSS ではユーザーがデータを削減できない

Browser Support

  • Chrome: behind a flag.
  • Edge: behind a flag.
  • Firefox: not supported.
  • Safari: not supported.

Source

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 と reduced-data メディアクエリを使用すると、10 件のリクエストと 172 KB のリソースが読み込まれます。これは 0.5 MB の節約になります。ユーザーはメディアをスクロールしていないため、追加のリクエストは行われません。

サムネイルが表示されず、多くのタイトルが表示されているテレビ番組のカルーセル インターフェースのスクリーンショット。

このデータ削減機能には、データ使用量の節約以外にもメリットがあります。より多くのタイトルが表示され、注意をそらすカバー画像もありません。多くのユーザーは、データ 1 メガバイトごとに料金を支払うため、データセーバー モードでブラウジングしています。CSS がここで役立つのは素晴らしいことです。

リソース

スクロール スナップ機能が制限されている

これらのスクロール スナップ提案の前は、カルーセル、スライダー、ギャラリーを管理する独自の JavaScript を記述すると、すべてのオブザーバーと状態管理がすぐに複雑になる可能性がありました。また、注意しないと、スクリプトによって自然なスクロール速度が正規化され、ユーザー操作が少し不自然に感じられたり、ぎこちなく感じられたりする可能性があります。

新しい API

snapChanging()

ブラウザがスナップ子をリリースすると、すぐにこのイベントが発生します。これにより、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 に組み込むことができ、インタラクションと状態をより明確でセマンティックな方法でオーケストレートできるようになります。

リソース

select 要素をカスタマイズする

<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() の後は、要素が子であるかどうかに関係なく、他の要素に対して要素を配置できます。また、デベロッパーは、どのエッジを基準に配置するかを指定したり、要素間の位置関係を作成するためのその他の便利な機能を利用したりできます。

詳細については、この説明で提供されている優れた例とコードサンプルをご覧ください。

リソース