次世代のウェブスタイル設定

最新の CSS の優れた機能について説明します。

現在、CSS では数多くの興味深いことが起こっており、その多くが今日のブラウザですでにサポートされています。CDS 2019 での講演では、注目を集める必要がある新機能と今後の機能をいくつか取り上げています。

この投稿では、現在使用できる機能に焦点を当てています。Houdini など、今後追加される機能の詳細については、講演をご覧ください。また、CSS@CDS ページでは、ここで説明するすべての機能のデモをご覧いただけます。

目次

スクロールスナップ

スクロール スナップを使用すると、ユーザーがコンテンツを垂直方向、水平方向、またはその両方にスクロールしたときのスナップ ポイントを定義できます。スクロールの慣性と減速が組み込まれており、タッチ対応です。

次のサンプルコードでは、子 <picture> 要素の左側に位置揃えされたスナップ ポイントを持つ <section> 要素の水平スクロールを設定します。

section {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
}

section > picture {
  scroll-snap-align: start;
}

仕組みは次のとおりです。

  • <section> 要素で、
    • overflow-xauto に設定して、水平方向のスクロールを許可します。
    • overscroll-behavior-xcontain に設定して、ユーザーが <section> 要素のスクロール領域の境界に達したときに、親要素がスクロールしないようにします。(これはスナップの必須というわけではありませんが、通常はおすすめです)。
    • ビューポートが常に最も近いスナップ ポイントにスナップされるように、scroll-snap-type を水平方向のスナップ用に xmandatory に設定します。
  • <picture> 要素では、scroll-snap-align が開始に設定されます。これにより、各画像の左側にスナップ ポイントが設定されます(directionltr に設定されている場合)。

ライブデモはこちらです。

また、縦方向のスクロール スナップマトリックス スクロール スナップのデモもご覧ください。

:focus-within

:focus-within は長年にわたるユーザー補助機能の問題に対処しています。支援技術のユーザーが UI にアクセスできるようにするために、子要素のフォーカスが親要素の表示に影響を与えるケースは数多くあります。

たとえば、複数のアイテムを含むプルダウン メニューがある場合は、いずれかのアイテムにフォーカスがある間はメニューを表示したままにします。切り替えないと、キーボード ユーザーのメニューが表示されなくなります。

:focus-within は、指定された要素の子要素にフォーカスがあるときにスタイルを適用するようブラウザに指示します。メニューの例に戻ると、メニュー要素に :focus-within を設定することで、メニュー項目にフォーカスがあるときに表示したままにすることができます。

.menu:focus-within {
  display: block;
  opacity: 1;
  visibility: visible;
}

「フォーカス」と「フォーカス内」の動作の違いを示すイラスト。

以下のデモでフォーカス可能な要素をタブで移動してみましょう。メニュー アイテムにフォーカスを合わせても、メニューは表示されたままになります。

メディアクエリ レベル 5

新しいメディアクエリを使用すると、ユーザーのデバイス設定に基づいてアプリのユーザー エクスペリエンスを効率よく調整できます。基本的にブラウザはシステムレベルの設定のプロキシとして機能し、CSS でメディアクエリの prefers-* グループを使用して応答できます。

システムレベルのユーザー設定を解釈するメディアクエリを示す図。

デベロッパーの皆様が最も喜んでくれそうな新しいクエリは以下のとおりです。

これらのクエリは、ユーザー補助において非常に役立ちます。以前は、たとえばユーザーが OS を高コントラスト モードに設定していたかどうかを知る方法はありませんでした。ウェブアプリでブランド イメージに忠実な高コントラスト モードを提供するには、アプリ内の UI から高コントラスト モードを選択してもらう必要がありました。これで、prefers-contrast を使用して OS から高コントラスト設定を検出できるようになりました。

これらのメディアクエリの利点の一つは、システムレベルのユーザー設定の複数の組み合わせで設計することで、幅広いユーザー設定とユーザー補助ニーズに対応できることです。薄暗い環境でも高コントラストのダークモードを使用できます。

Adam にとって大事なのは、「動きが抑えられたことを好む」は「動きなし」として実装されないことです。ユーザーは、アニメーションが必要ではなく、動きが少ない方が好ましいと言っています。彼は、縮小された動きは動きではないと主張しています。ユーザーがモーションの軽減を好む場合に、クロスフェード アニメーションを使用する例を次に示します。

論理プロパティ

論理プロパティは、多くのデベロッパーが多言語化に取り組むなかで注目を集めている問題を解決します。marginpadding などの多くのレイアウト プロパティは、上から下、左から右に読む言語を想定しています。

従来の CSS レイアウト プロパティを示す図。

書くモードが異なる複数の言語のページをデザインする場合、デベロッパーは複数の要素にわたってこれらすべてのプロパティを個別に調整しなければならず、これが保守性の悪夢になります。

論理プロパティを使用すると、変換中や書き込みモードでレイアウトの整合性を維持できます。コンテンツの空間配置ではなく、コンテンツの意味的な順序に基づいて動的に更新されます。論理プロパティでは、各要素に次の 2 つの次元があります。

  • ブロック ディメンションは、行内のテキストの流れに対して垂直です。(英語では、block-sizeheight と同じです)。
  • インライン ディメンションは行内のテキストの流れに平行です。(英語では、inline-sizewidth と同じです)。

これらのディメンション名は、すべての論理レイアウト プロパティに適用されます。したがって、たとえば英語では、block-starttop と同一で、inline-endright と同じです。

新しい CSS 論理レイアウト プロパティを示す図。

論理プロパティを使用すると、ページの writing-mode プロパティと direction プロパティを変更するだけで、他の言語のレイアウトを自動的に更新できます。個々の要素のさまざまなレイアウト プロパティを更新する必要はありません。

以下のデモでは、<body> 要素の writing-mode プロパティにさまざまな値を設定して、論理プロパティの仕組みを確認できます。

position: sticky

position: sticky が指定された要素は、画面外に出始めるまでブロックフローの状態を維持します。画面外に出ると、ページの残りの部分でのスクロールが停止され、要素の top 値で指定された位置に固定されます。その要素に割り当てられたスペースはフロー内に残り、ユーザーが上にスクロールすると要素に戻ります。

固定配置を使用すると、これまで JavaScript が必要だったさまざまな効果を生み出すことができます。その可能性を示すために、いくつかのデモを作成しました。各デモではほぼ同じ CSS を使用し、HTML マークアップをわずかに調整してそれぞれの効果を作成しています。

スティッキー スタック

このデモでは、すべての固定要素が同じコンテナを共有しています。つまり、ユーザーが下にスクロールすると、各固定要素が前の固定要素の上にスライドします。固定要素は同じ固定位置を共有しています。

固定スライド

ここでは、スティッキー要素がいとこです。(つまり、両親は兄弟姉妹です)。追尾型要素がコンテナの下限に達すると、コンテナと一緒に上に移動し、下位の固定要素が上位のコンテナを押し上げているような印象を与えます。つまり、固定された位置をめぐって競合しているように見えます。

スティッキー デスペラード

Sticky Slide と同様に、このデモの固定要素もいとこです。ただし、2 列のグリッド レイアウトに設定されたコンテナに配置されています。

backdrop-filter

backdrop-filter プロパティを使用すると、要素自体ではなく、要素の背後の領域にグラフィック効果を適用できます。これにより、これまでは複雑な CSS や JavaScript を使ったハッキングでしか実現できなかった多くの素晴らしい効果を、CSS を 1 行追加するだけで実現できます。

たとえば、このデモでは backdrop-filter を使用して OS スタイルのぼかし処理を実現しています。

backdrop-filter に関する有用な投稿がすでにありますので、そちらで詳細をご確認ください。

:is()

:is() 疑似クラスは実際には 10 年以上前のものですが、まだ十分に活用されていない状態です。セレクタのカンマ区切りリストを引数として受け取り、そのリスト内のすべてのセレクタに一致します。その柔軟性によって非常に便利になり、配送する CSS の数を大幅に削減できます。

簡単な例:

button.focus,
button:focus {
  …
}

article > h1,
article > h2,
article > h3,
article > h4,
article > h5,
article > h6 {
  …
}

/* selects the same elements as the code above */
button:is(.focus, :focus) {
  …
}

article > :is(h1,h2,h3,h4,h5,h6) {
  …
}

gap

以前から、CSS グリッド レイアウトには gap(以前の grid-gap)がありました。gap を使用すると、子要素の周囲の間隔ではなく、含まれる要素の内部の間隔を指定することで、レイアウトに関する多くの一般的な問題を解決できます。たとえば、ギャップを使用すると、子要素の余白によって、含まれる要素の端に不要な空白が生じることを心配する必要がなくなります。

gap プロパティによって、コンテナ要素の端の周囲の意図しないスペースが回避される仕組みを示す図。

さらに嬉しいことに、gap が Flexbox に導入されます。グリッドの間隔特典と同じものがすべて提供されます。

  • スペースの宣言は 1 つで、多数あります。
  • プロジェクトでは、どの子要素にスペースを割り当てるかについて規則を確立する必要はありません。スペースは、親要素に割り当てられます。
  • このコードは、lobotomized owl のような古い戦略よりも簡単に理解できます。

次の動画では、2 つの要素(1 つはグリッド レイアウト、もう 1 つは Flex レイアウト)に対して 1 つの gap プロパティを使用するメリットを示しています。

現時点では、Flex レイアウトで gap をサポートしているのは FireFox のみですが、次のデモで動作を確認してみてください。

CSS Houdini

Houdini は、ブラウザのレンダリング エンジン用の低レベル API のセットで、カスタム CSS の解釈方法をブラウザに指示できます。つまり、CSS オブジェクト モデルにアクセスして、JavaScript で CSS を拡張できるようにします。これには、さまざまなメリットがあります。

  • これにより、カスタム CSS 機能をより柔軟に作成できます。
  • レンダリングに関する問題をアプリケーション ロジックから簡単に分離できます。
  • ブラウザがスクリプトを解析して 2 回目のレンダリング サイクルを実行する必要がなくなるため、現在 JavaScript で行っている CSS ポリフィルよりもパフォーマンスが高くなります。Houdini のコードは、最初のレンダリング サイクルで解析されます。

従来の JavaScript ポリフィルと比較した Houdini の仕組みを示すイラスト。

Houdini は、複数の API の総称です。これらの詳細と現在のステータスについては、Is Houdini Ready Yet? をご覧ください。今回の講演では、Properties and Values API、Paint API、アニメーション ワークレットについて説明しましたが、これらは現時点で最もサポートされている API です。これらの各 API については、簡単に記事を投稿できますが、今のところは、Google の講演で概要と便利なデモをご覧いただき、API を使って何ができるかを感じていただけますか?

オーバーフロー

まだ説明したい内容がまだいくつか残っていますが、詳しく説明する時間がありませんでした。そこで速報で説明しました。Crashlytics の機能についてまだご存じない方は、トークの最後の部分をご視聴ください。

  • size: 高さと幅を同時に設定できるプロパティ
  • aspect-ratio: 本質的に持たない要素のアスペクト比を設定するプロパティ
  • min()max()clamp(): 幅と高さだけでなく、任意の CSS プロパティに数値制約を設定できる関数
  • 既存のプロパティを list-style-type するが、まもなく、絵文字や SVG を含む幅広い値をサポートする予定
  • display: outer inner: display プロパティがまもなく 2 つのパラメータを受け入れるようになります。これにより、inline-flex などの複合キーワードを使用せずに、外側と内側のレイアウトを明示的に指定できます。
  • CSS リージョン: 長方形以外の指定された領域にコンテンツを配置できます。
  • CSS モジュール: JavaScript で CSS モジュールをリクエストして、操作しやすいリッチ オブジェクトを取得できるようになります。