CSS 2022 の現状

Google IO 2022 で紹介されている現在と未来のウェブ スタイル設定機能とその他の機能。

2022 年は、機能とブラウザの連携機能リリースの両方において、CSS が最も優れた年の 1 年となる年となるようになっており、14 の機能を実装するという目標を共同で掲げています。

概要

この投稿は、Google IO 2022 で行われた講演の記事形式です。各機能の詳細なガイドではなく、興味を引くための導入と概要であり、深さではなく幅広さを提供します。興味がある場合は、セクションの最後にあるリソースリンクで詳細を確認してください。

目次

以下のリストを使用して、関心のあるトピックに移動できます。

ブラウザの互換性

このような多くの CSS 機能が連携的にリリースされる主な理由は、相互運用 2022 の取り組みによるものです。相互運用の取り組みを調査する前に、Compat 2021 の取り組みを確認することが重要です。

互換 2021

アンケートを通じたデベロッパーからのフィードバックを受け、2021 年の目標は、現在の機能の安定化、テストスイートの改善、次の 5 つの機能のブラウザの合格スコアの向上でした。

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

テストのスコアが全面的に向上し、安定性と信頼性が向上したことが実証されました。チームの皆さま、心からお祝いを申し上げます。

相互運用 2022

今年は各ブラウザが一堂に会し、目指していた機能と優先事項について話し合い、力を合わせました。同社はデベロッパー向けに次のウェブ機能を提供する予定でした。

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

胸躍る、意欲的なリストですので、今後の展開を楽しみにしています。

2022 年の最新情報

当然のことながら、CSS 2022 の状態は、相互運用 2022 の取り組みによって劇的に影響を受けます。

レイヤをカスケード

対応ブラウザ

  • 99
  • 99
  • 97
  • 15.4

ソース

最後に読み込まれたスタイルは以前に読み込まれたスタイルを上書きできるため、@layer 以前は、読み込まれたスタイルシートの検出順序が非常に重要でした。これにより、エントリ スタイルシートが入念に管理され、デベロッパーは重要度の低いスタイルを最初に読み込んでから、重要度の高いスタイルを読み込む必要がありました。ITCSS など、デベロッパーがこの重要度を管理するのを支援する全体的な手法が存在します。

@layer を使用すると、エントリ ファイルでレイヤとその順序を事前に定義できます。次に、スタイルの読み込み、読み込み、定義をレイヤ内に配置できます。これにより、読み込みのオーケストレーションを注意深く管理しなくても、スタイルのオーバーライドの重要度を保持できます。

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

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

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

リソース

サブグリッド

対応ブラウザ

  • 117
  • 117
  • 71
  • 16

ソース

subgrid 以前は、別のグリッドの内側にあるグリッドを、その親セルまたはグリッド線に揃えることができませんでした。グリッドのレイアウトはそれぞれ異なっていました。デザイナーの多くは、デザイン全体に 1 つのグリッドを配置し、そのグリッド内で常にアイテムを配置します。これは CSS では実現できません。

subgrid の後、グリッドの子は、その親の列または行を独自の列として引き継いで、親または子を親に合わせて配置できます。

次のデモでは、body 要素によって 3 列からなるクラシック グリッドが作成されます。中央の列は main と呼ばれ、左右の列には fullbleed という名前が付いています。次に、本文内の各要素(<nav><main>)は、grid-template-columns: subgrid を設定することで、body の名前付き行を採用します。

​​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 によって定義された線を表示しているサブグリッドのデモのスクリーンショット。

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

どの要素のグリッド レイアウトまたはサブグリッド レイアウトのラベルが設定されているかを示す Chrome DevTools の [要素] パネルのスクリーンショット。
Firefox Devtools のスクリーンショット

リソース

コンテナクエリ

対応ブラウザ

  • 105
  • 105
  • 110
  • 16

ソース

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

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

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

これらのスタイルにより、次の動画の Mon、Tues、Wed、Thurs、Fri の各列をイベント要素からクエリできるようになります。

デモ 作成者: Una Kravets

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

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

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

別の例を次に示します。1 つの書籍コンポーネントは、ドラッグ先の列で利用可能なスペースに合わせて調整されます。

デモ

状況の評価については Una が正解です。@container を使用する際には、多くのエキサイティングで意味のある設計上の決定を行う必要があります。

リソース

accent-color

対応ブラウザ

  • 93
  • 93
  • 92
  • 15.4

ソース

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 はすべての処理を動的かつ適切なタイミングで行うことができます。テーマ設定やデータ可視化の色を有効にするために、CSS と JavaScript の多数の KB をユーザーに送信するのではなく、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()

対応ブラウザ

  • 101
  • 101
  • 96
  • 15

ソース

HWB は色相、白色、黒さの略です。これは単に色相と、明るくしたり暗くしたりするための白または黒の分だけなので、人間が理解しやすい色を明確に表現します。白や黒と色を混ぜるアーティストは、このカラー構文の追加を気に入っているかもしれません。

この色関数を使用すると、HSL や RGB と同じ sRGB 色空間から色が生成されます。2022 年の新機能として 新しい色はありませんが 構文やメンタルモデルに関心を持つユーザーにとって

リソース

色空間

色の表現方法は色空間で決まります。各色空間には、色に関するさまざまな機能とトレードオフがあります。明るい色をすべてまとめるものもあれば、明度に基づいて最初に並べるものもあります。

2022 年の CSS では、10 種類の新しい色空間が提供される予定です。色空間にはそれぞれ、デザイナーやデベロッパーが色を表示、選択、組み合わせする際の独自の機能が用意されています。これまで、色を扱うオプションは sRGB のみでしたが、CSS では新たな可能性と新しいデフォルトの色空間である LCH が利用可能になりました。

color-mix()

対応ブラウザ

  • 111
  • 111
  • 113
  • 16.2

ソース

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()

対応ブラウザ

  • x
  • x
  • x

ソース

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 言語自体に適切なコントラストの配色を選択することで、アクセスしやすく読みやすいインターフェースを提供しやすくなることをご検討ください。

リソース

相対色の構文

対応ブラウザ

  • 111
  • 111
  • 113
  • 15

ソース

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

相対色の構文の後は、任意のスペースの色を分解、変更し、色として返すことができます。これらすべてを CSS の 1 行で実行できます。HSL にこれ以上の制限はありません。任意の色空間で操作ができ、HSL を容易にするために作成する必要のあるカスタム プロパティははるかに少なくなります。

次の構文例では、16 進数を基本として指定し、それに基づいて 2 つの新しい色を作成しています。1 つ目の色 --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 列のスクリーンショット。各列は中央の列よりも暗めまたは明る。
デモを試す

この関数はカラーパレットの生成にも使用できます。以下は、指定したベースカラーからパレット全体を生成するデモです。この CSS の 1 セットがさまざまなパレットに使用でき、各パレットは異なるベースを提供するだけです。ボーナスとして、私は 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

対応ブラウザ

  • 102
  • 102
  • 112
  • 15.5

ソース

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

リソース

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 アットルールです。カスタム プロパティの場合と同様に、-- で始まるカスタム名を指定する方法に注目してください。

@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)の 1 つがありました。これらは多くの点でうまく機能しましたが、モバイル ブラウザでは複雑さが生まれました。

モバイルでは、ページを読み込むときに 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()

対応ブラウザ

  • 105
  • 105
  • 121
  • 15.4

ソース

:has() 以前は、selectorサブジェクトが常に末尾にありました。たとえば、このセレクタのサブジェクトはリストアイテム 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> がある場合は、画像のスタイルを調整します。次の例では、blobstore を含む図が選択され、そのコンテキスト内の画像が選択されます。:has() は使用され、ターゲットは図ではなく画像であるため、被写体は変更されません。

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

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

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

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

リソース

2022 年以降

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

次のセクションからわかることは、これらのソリューションが 2023 年にリリースされる予定ではなく、ここに挙げた多くの企業から解決を求める多くの企業が抱えている問題であることに確信を持てるはずです。

大まかに入力されたカスタム プロパティ

対応ブラウザ

  • 85
  • 85
  • 16.4

ソース

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-shadowvar(--x) を使用し、その後 --x: red が試行された場合、red<length> ではないため無視されるようになりました。つまり、いずれかのカスタム プロパティに無効な値が指定された場合でも、シャドウは引き続き機能します。失敗する代わりに、initial-value0px に戻ります。

アニメーション

型安全性に加えて、アニメーションの可能性も広がります。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);

定義したので、そのうちの 1 つを以下のように使用できます。

@media (--OSdark) {
  :root {
    …
  }
}

CSS カスタム プロパティ ライブラリの Open Props 内で使用しているカスタム メディアクエリの一覧を確認する。

リソース

ネストセレクタは便利です

@nest 以前は、スタイルシートの繰り返しが多くありました。特に、セレクタが長く、それぞれが小さな差異を目標にしていた場合、扱いづらくなっていました。ネストの便利さは、プリプロセッサを採用する最も一般的な理由の一つです。

@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 は、全体的なスタイルの整理、一元化、所有権に役立ちます。コンポーネントは、他のスタイル ブロックに分散させるのではなく、独自のスタイルをグループ化して所有できます。これらの例では小さく見えるかもしれませんが、利便性と読みやすさの両方において、非常に大きな影響を及ぼす可能性があります。

リソース

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

対応ブラウザ

  • 118
  • 118
  • x
  • 17.4

@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 でしか実行できません。次の例では、img スタイルと .content スタイルは、.media-block の子が .content の兄弟または親である場合のみ適用されます。

@scope (.media-block) to (.content) {
  img {
    border-radius: 50%;
  }

  .content {
    padding: 1em;
  }
}

リソース

メーソンリー レイアウトに CSS を使用できない

CSS とグリッドを使用する前は、列や Flexbox を使用する CSS メソッドではコンテンツの順序が不正確になるため、JavaScript がメーソンリー レイアウトを実現する最善の方法でした。

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 はユーザーによるデータ削減を支援できない

対応ブラウザ

  • x
  • x

ソース

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 メガバイトの節約であり、ユーザーはメディアをまったくスクロールすることすらなく、その時点で追加のリクエストは行われません。

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

このようにデータ エクスペリエンスが低下することには、単にデータを節約できるだけでなく、さらに多くのメリットがあります。より多くのタイトルが表示されるようになり、気を散らすほどの気を散らす表紙の画像は使用されていません。多くのユーザーがデータセーバー モードで閲覧します。これは、課金がメガバイト単位のデータで行われるためです。ここで CSS のサポートを受けられるのはとても助かります。

リソース

スクロール スナップ機能が限定的すぎる

このようなスクロール スナップの提案が行われる以前は、カルーセル、スライダー、ギャラリーを管理する独自の 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() の後、デベロッパーは、要素が子であるかどうかにかかわらず、他の要素に対して要素を配置できます。また、デベロッパーは、どのエッジに対して配置するかを指定するなど、要素間の位置関係を作成するための細かな指定ができます。

説明には、いくつかの優れた例とコードサンプルが用意されています。

リソース