📎

あっ、そうだ!モダンCSSをまとめておこう

2024/01/14に公開

2023年もCSSの進化がすごかったですね!
その進化を2024年でも生かしていけるように、今回まとめておいていつでも参照できるように記事を書こうと思いました。

お読みいただけると幸いです。
一緒に2024年もスタートダッシュで走り抜けましょう。

まず、はじめに

この記事では、最近登場した、エキサイティングで、アクロバティックでファンタジックなインパクトのある機能をピックアップして紹介したいと思います。
CSSの多彩な新機能を広く紹介することで、読者がこれらに触れる機会を持てるように努めています。
特に興味を引く機能があれば、他の媒体を通じて更に詳しく掘り下げることをお勧めします。

コンテナクエリ 〜 レスポンシブデザインの新時代の到来

最近のウェブ開発では、レスポンシブデザインが不可欠です。これまでのメディアクエリによるアプローチは有効ですが、2023年に登場したCSSのコンテナクエリは、レスポンシブデザインをさらに進化させる機能です。

コンテナクエリは、親要素のサイズに基づいてスタイルを適用することができます。これにより、コンテナごとに独立したレイアウトの調整が可能になり、より柔軟で複雑なデザインが実現できます。

例として、商品カードのレイアウトを考えてみましょう。以下のコードは、カードコンテナの幅に応じて、カードのスタイルを動的に変更します。

コンテナの設定
container-type: inline-size;はコンテナのタイプを指定し、この場合はコンテナの幅(inline-size)に基づいてクエリが適用されます。containerプロパティというショートハンドもあるので、そちらを使用してもいいかもしれませんね。

.product-container {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  padding: 10px;
  container-type: inline-size; /* コンテナタイプを設定 */
}

container-typeプロパティの詳細はこちら。
https://developer.mozilla.org/ja/docs/Web/CSS/container-type

クエリを設定する
@containerを使って、クエリを設定します。

/* 幅が500px以上のときのスタイル */
@container (width >= 500px) {
  .product-card {
    background-color: lightblue; /* 背景色を青に変更 */
    flex-basis: calc(33.333% - 10px); /* 幅を変更 */
    font-size: initial; /* フォントサイズをリセット */
  }
}

widthが500px以上だったら、背景色とcardの幅の変更とフォントサイズを変更しています。

CodePenでいろいろ遊んでみてくださいね。

スタイルクエリ 〜 デザインの可能性を広げていこう

次は、スタイルクエリです。
「スタイルクエリ」とは何かといいますと、親コンテナのスタイルに基づき、その子要素のスタイルを定義できるCSSの機能です。
Chromeのバージョン111から部分的に実装されており、CSSカスタムプロパティを活用することで、コンテナのスタイルを柔軟に指定できるようになります。
まだ完全にはサポートしていないので、詳しくは各ブラウザの開発者ドキュメントなどをチェックしてください。

参考として、Can I Useの情報を載せておきます。

https://caniuse.com/mdn-css_at-rules_container_style_queries_for_custom_properties

ここでは例として、天気に応じてカードの背景やアイコンを変更するサンプルコードを紹介します。

@container style(--sunny: true) {
  .weather-card {
    background: linear-gradient(-30deg, yellow, orange);
  }
  .weather-card:after {
    content: url(<data-uri-for-demo-brevity>);
    background: gold;
  }
}

このコードでは、--sunnyというカスタムプロパティがtrueであれば、.weather-cardクラスに晴れの日に相応しいスタイルが適用されます。

HTMLは以下となります。

   <li class="card-container" style="--sunny: true;">
    <div class="weather-card">
      <div class="day">Saturday</div>
      <div class="date">February <span>12</span></div>
      <div class="temps">
        <div class="high">High: <span>55</span></div>/
        <div class="low">Low: <span>47</span></div>
      </div>
      <div class="features">
        Clear skies, sun
      </div>
    </div>
  </li>

親コンテナにstyle="--sunny: true;"を指定しています。これにより、weather-cardのスタイルが切り替わるということです。
これはいろいろな場面で活用できそうですね。

ちなみにandを使用して、スタイルを組み合わせることもできます。

@container style(--sunny: true) and style(--cloudy: true) 
  <li class="card-container" style="--cloudy: true; --sunny: true;">

今後は、ブーリアンクエリや値の範囲を利用したレンジクエリといった進化も予定されており、CSSのデザインの可能性はさらに広がります。デザイナーやフロントエンド開発者にとっても、とても興味深い展開ではないでしょうか。

スタイルクエリの導入により、CSSの世界に新たな一歩が踏み出されました。これからどんな魅力的なデザインが生まれるのか、楽しみですね。

:has()セレクタ 〜 いわゆる最も強力なCSSの新機能だなっ

:has()セレクタを紹介したいと思います。これはまさにCSSの世界に新たな風を吹き込む機能です。
今までは親要素に基づいて子要素を選択することはできましたが、その逆は不可能でした。しかし、:has()の登場により、それが可能となります。

たとえば、:has()を使って「特定のクラスを持つ子要素を含む親要素だけにスタイルを適用する」といったことが可能になります。これは、デザインの細かい調整や、より複雑なレイアウトを実現する際に非常に有用です。

以下に、:has()セレクタの使用例を示します。
ある商品リストがあり、その中にセール中の商品が含まれている場合に、そのリスト全体に特別なスタイルを適用したいとしましょう。こういう場合に:has()の出番が回ってきます。

/* セール中の商品を含む製品リストに特別なスタイルを適用 */
.product-list:has(.product.on-sale) {
  border: 2px solid red;
  background-color: lightyellow;
}

/* セール中の商品に適用されるスタイル */
.product.on-sale {
  color: red;
  font-weight: bold;
}
<div class="product-list">
  <div class="product">
    <p>商品A</p>
    <p>価格: ¥1,000</p>
  </div>
  <div class="product on-sale">
    <p>商品B - セール中!</p>
    <p>価格: ¥800</p>
  </div>
  <div class="product">
    <p>商品C</p>
    <p>価格: ¥1,200</p>
  </div>
</div>

あとモーダルを開いたときに、親の画面のスクロールが操作されてしまうような場合、無効にするのにも使えます。

html:has(dialog[open]) {
  overflow: hidden;
}

:nth-child()の「of S」構文 〜 新しいCSSセレクタの可能性

次は:nth-child()セレクタの「of S」構文。これは、特定のパターンに一致する子要素を選択するための強力なツールです。
従来の:nth-child()セレクタは、親要素の子要素の中から特定の順序(例えば、3番目や5番目など)の要素を選択するのに使われてきました。しかし、「of S」構文を使うと、特定のクラスやタイプの子要素の中で特定の順序にある要素を選択することができるようになります。
例えば、.itemクラスを持つ子要素のうち、3番目の要素だけにスタイルを適用したい場合、以下のように書きます。

.container :nth-child(3 of .item) {
  color: red;
}

このセレクタは、.containerクラスを持つ要素の子要素の中で.itemクラスを持つもののうち、3番目の要素にマッチします。

例えば、ニュース記事のリストがあるとして、特定のカテゴリー(クラス名で表される)の記事のみに特定のスタイルを適用する場合を考えてみましょう。

以下は、ニュース記事のリストにおいて「スポーツ」カテゴリーの記事のうち、3番目の記事に特別なスタイルを適用するサンプルコードです。

この例では、.news-list内の.sportsクラスを持つニュースアイテムのうち、3番目に来る要素(この場合は「スポーツの記事3」)に、特定のスタイルが適用されます。

:nth-child() の「of S」構文を使用することで、特定のカテゴリーに属するアイテムの中で特定の順序にあるものにスタイルを適用できるのがわかったと思います。この構文は、ウェブページ上のリストやグリッドレイアウトを扱う際に便利そうです。

text-wrap: balance 〜 気軽に読みやすさを向上させちゃおうぜ

次は、text-wrap: balanceです。このプロパティは、ウェブページ上のテキストの折り返しをより美しく、読みやすくするためのものです。

従来のウェブページでは、テキストは通常、コンテナの幅に合わせて折り返されます。しかし、これによって行の長さが不均等になることがあり、特に多列レイアウトでは読みにくさを感じることがありました。

text-wrap: balanceプロパティを使用すると、テキストの行がコンテナ内で均等に分散されるようになります。これにより、特に新聞のような多列レイアウトにおいて、各列の行の長さが均一になり、読みやすくなります。

例えば、以下のように使用することができます。

.article {
  text-wrap: balance;
}

このCSSを適用すると、.articleクラスを持つ要素内のテキストが、均等に折り返されるようになります。

text-wrap: balanceは、特に新聞や雑誌のようなコンテンツ、または、複数の短い段落からなる記事において、視覚的なバランスと読みやすさを改善するのに非常に効果的です。

違いは以下のサンプルを見てもらうと分かりやすいです。

行数やパフォーマンスに注意点がありますので、以下を参照していただければと思います。
https://developer.chrome.com/docs/css-ui/css-text-wrap-balance?hl=ja

initial-letter 〜 CSSで美しいイニシャルレターを実現してしまおう

次はinitial-letterです。このプロパティを使えば、文章の最初の文字を大きく装飾する「イニシャルレター」が簡単に作れます。

イニシャルレターは、特に雑誌や書籍でよく見られるデザインテクニックで、読者の注意を引き付けると同時に、記事や章の始まりを華やかに演出します。ウェブでも、この技法を用いることで、コンテンツをより引き立たせることができるのです。

initial-letterプロパティは、指定した文字のサイズを行数単位で大きく表示するために使用します。例えば、次のように使います。

p::first-letter {
  initial-letter: 3;
  font-weight: bold;
}

この例では、段落(<p>)の最初の文字を3行分の高さに拡大し、太字にしています。これにより、テキストが目を引くスタートを切り、読者の関心を高めることができます。

次はサンプルコードです。

このサンプルでは、<article>内の各<p>タグの最初の文字に対して、initial-letterプロパティを適用しています。ここでは、最初の文字を3行分の高さにし、2行分下に沈ませるように設定しています。さらに、文字のサイズを大きくし、太字にして、色を青系にしています。右側のマージンと行の高さを調整し、左側に浮かせることで、周囲のテキストとのバランスを取っています。

このスタイルを適用することで、文章の最初の文字が目を引くデザインになり、全体のレイアウトが洗練された印象を与えますね。

詳細は以下をご覧ください。
https://developer.mozilla.org/ja/docs/Web/CSS/initial-letter

またinitial-letterの挙動を確認するには、以下のサンプルコードを見ると分かりやすいです。

ダイナミックビューポート単位 〜 レスポンシブデザインの救世主

次にダイナミックビューポート単位についてご紹介します。

従来のビューポート単位(vhvwvminvmax)は、ビューポートの初期サイズに基づき、要素のサイズを決定します。しかし、これらの単位ではビューポートのサイズが固定されるため、モバイル端末でナビゲーションバーが表示されたり隠れたりすると、ページの内容が長くなりすぎてスクロールが必要になることがあります。これに対して、ダイナミックビューポート単位は、ビューポートのサイズが変更されると、要素のサイズも動的に調整されます。

この機能により、追加の動的なブラウザツールバー(例えば、上部のバーやタブバーにあるアドレスバーなど)が表示された場合でも、ウェブページのレイアウトが適切に調整され、柔軟なレスポンシブデザインを実現できます。

具体的には、以下の新しい単位が追加されています。

  • svh, svw: 小さなビューポートの高さと幅、つまり最小のアクティブビューポートサイズを表します。
  • lvh, lvw: 大きなビューポートの高さと幅、つまり最大のアクティブビューポートサイズを表します。
  • dvh, dvw: ダイナミック(動的な)ビューポートの高さと幅を指します。

広色域のカラースペース 〜 今まで指定できなかった色を指定しちゃうぜ。ワイルドだろ

次は広色域のカラースペースについてお話しましょう。この技術は、ウェブページ上でより豊かで鮮やかな色彩を表現するために非常に重要です。

従来のウェブデザインでは、sRGBカラースペースが一般的に使用されていました。sRGBはウェブ用に特別に設計されたカラースペースで、多くのデバイスによってサポートされています。しかし、sRGBは色域が限られており、ある程度の色しか表現できません。

対照的に、広色域のカラースペース(例えば、Adobe RGBやDCI-P3など)は、より多くの色をカバーできます。これにより、より鮮やかでリアルな色彩表現が可能になり、特に高品質な画像やビデオをウェブページに表示する際にその差が顕著になります。

以下はサンプルコードになります。

DevToolsで確認すると、白い線でsRGB範囲の終了位置、高色域の色範囲の開始位置を示していることがわかります。
DevTools

また新しいウェブのカラー選択ツールなどもありますのでそちらを使ってみても良いかと思います。
https://gradient.style/

color-mix() 〜 色と色をがっちゃんこして新しい色をつくる関数ができました

CSSに新たに加わった魅力的な関数、color-mix()についてご紹介します。この関数は、異なる色を混ぜ合わせて新しい色を作るために使われます。

従来のウェブデザインでは、特定の色を作り出すためにRGB値やHSL値を手動で調整する必要がありました。しかし、color-mix()を使うと、既存の色を基にして、簡単に新しい色を作成できるようになります。

この関数の基本的な形式は以下の通りです。

color-mix(method, color1[ p1], color2[ p2])

例えば、青と白色を半々に混ぜたい場合、次のように書きます。

.element {
  background-color: color-mix(in srgb, blue 50%, white);
}

このコードでは、.elementクラスの背景色を青と白色を半々に混ぜた色に設定しています。これにより、独自の緑色のような色が生成されます。

color-mix()関数を活用することで、ウェブデザインにおける色の表現力が大幅に向上します。ブランドカラーやデザインテーマに合わせて、柔軟に色を調整することが可能になりました。是非活用していきましょう。

以下はcolor-mix()のplaygroundです。いろいろ試してみてください。

CSSのカラー指定については以下のサイトを参考とさせていただきました。奥が深い…。
https://griponminds.jp/blog/relearn-css-color/

ネスト 〜 Sassじゃなくてもネストできる時代がやってきました

ネストは、特に大規模なウェブサイトや複雑なデザインプロジェクトにおいて、コードの可読性と管理を効果的に向上させる手段です。

ネストとは、CSSルールの中で他のルールを記述することで、親子関係やコンポーネントの構造を明確に表現できるようにする方法です。これにより、セレクタの繰り返しを減らし、より直感的にスタイリングを行うことができます。

例えば、以下のようにネストを使用することができます。

.navbar {
  background-color: navy;
  color: white;

  .menu-item {
    padding: 10px;
    border-bottom: 1px solid gray;

    &:hover {
      background-color: lightblue;
    }
  }
}

このコードでは、.navbarクラスに基本的なスタイルを設定し、その中に.menu-itemのスタイルをネストしています。さらに、.menu-itemのホバー時のスタイルもネストの中に記述しています。

ネストを使用することで、CSSの構造が親子関係を反映し、どのスタイルがどの要素に関連しているかが明確になります。

ネストを利用することで、コードの可読性が向上し、保守や更新が容易になります。

またメディアクエリや前述のコンテナクエリをネストすることもできます。
前述のコンテナクエリのサンプルコードをネストを使用する方法で書き直してみました。

カスケードレイヤ 〜 CSSをレイヤで管理

次はカスケードレイヤについてお話ししましょう。カスケードレイヤは、CSSのルールをより整理された形で管理し、スタイルの優先順位を明確にするための強力なツールです。

従来のCSSでは、スタイルの競合や優先順位の問題を解決するために、特定のセレクタの重みや!importantルールを使う必要がありました。しかし、これらの方法はコードの複雑さを増す原因となることがありました。

カスケードレイヤを使用すると、スタイルシート内で明確な「レイヤ」を定義し、それぞれのレイヤに異なるスタイルルールを割り当てることができます。これにより、スタイルの競合を減らし、コードの可読性を高めることが可能になります。

例えば、以下のようにレイヤを定義して使用することができます。

@layer base, components, utilities;

@layer base {
  body {
    font-family: sans-serif;
    background: #f3f3f3;
  }
}

@layer components {
  .button {
    padding: 10px 15px;
    border-radius: 5px;
  }
}

@layer utilities {
  .margin-top {
    margin-top: 20px;
  }
}

この例では、basecomponentsutilitiesという3つのレイヤを定義しています。各レイヤには、その役割に応じたスタイルが割り当てられています。たとえば、ベーススタイルはbaseレイヤに、コンポーネントのスタイルはcomponentsレイヤに、ユーティリティクラスはutilitiesレイヤー配置されます。

カスケードレイヤを利用することで、スタイルシート内のルールがより明確に分類され、管理が容易になります。これは特に、大規模なプロジェクトや複数の開発者が関わるプロジェクトにおいて、スタイルの整合性を保つのに役立ちます。

カスケードレイヤの導入により、CSSのコードをより効率的に、そして直感的に管理することが可能になります。

レイヤは@layerルールを使って宣言されます。レイヤが宣言された順序が、そのレイヤ内のCSSルールの優先順位を決定します。

@layer base, components, utilities;

サンプルコードです。

このサンプルコードでは、次のようなスタイリングを行っています。

  • baseレイヤで.containerの背景色とパディングを設定。
  • componentsレイヤで.buttonのスタイルを定義。
  • utilitiesレイヤで.margin-topクラスを使用して上部の余白を追加。

カスケードレイヤを使うことで、各スタイルの責任を明確に分離し、CSSの保守や更新が容易になります。また、レイヤ間での優先順位が明確になり、スタイルの競合を解決しやすくなります。

その他カスケードレイヤの詳細は以下をご覧ください。
https://developer.chrome.com/blog/cascade-layers?hl=ja

スコープCSS 〜 局所的スタイリングの活用

次はスコープCSSに焦点を当ててみましょう。スコープCSSは、特定のHTMLセクションやコンポーネントに対してCSSスタイルを限定的に適用するためのアプローチです。これにより、スタイルの意図しない影響を避けると同時に、コードの保守性を向上させることができます。

従来のグローバルCSSでは、スタイルがドキュメント全体に適用されるため、異なるコンポーネント間でスタイルの競合が生じることがありました。しかし、スコープCSSを使用すると、特定のHTML要素やコンポーネントに対してスタイルを「隔離」し、その影響範囲を限定できます。

例えば、@scopeでスコープCSSを使う方法は以下のようになります。

@scope (.card) {
  .button {
    background-color: blue;
    color: white;
  }
}

この例では、.cardクラスを持つ要素内の.buttonクラスにだけ、そのスタイルが適用されます。そのため外部の.buttonには影響を及ぼしません。

スコープCSSは、特に大規模なプロジェクトやコンポーネントベースのアーキテクチャを採用している場合に役立ちます。スタイルの競合を減らし、コードベースをより整理しやすくすることで、開発プロセス全体がスムーズになります。

以下サンプルコードです。

三角関数 〜 CSSで数学的な美しさを表現

CSSで導入された三角関数について探究してみましょう。これらの関数は、ウェブデザインに数学的な表現を取り入れる新しい方法を提供します。

三角関数は、特にアニメーションや複雑なレイアウトを作成する際に非常に有効です。CSSでは、sin(), cos(), tan()といった基本的な三角関数が利用できるようになりました。これにより、要素の位置や形状を動的に計算し、自然な動きや形状を作成することが可能です。

たとえば、円運動のアニメーションを作成する場合、sin()cos()関数を使用して、要素の位置を計算することができます。

 /* index番号を取得して角度を計算 */
 --angle: calc(360deg / 8 * var(--index));

 /* 座標位置を計算 */
 --x: calc((50% + 50px) * cos(var(--angle)));
 --y: calc((50% + 50px) * sin(var(--angle)));

CSSで動的なデザインを作成する際、カスタムプロパティとcalc()関数の組み合わせは非常に強力です。ここでは、円周上の要素の位置を決定するためにこれらを使用しています。

まず、--angleというカスタムプロパティで、各要素の円周上の角度を計算します。これは360degを要素の数(この例では8)で割り、それに要素のインデックス(--index)を掛けることで求められます。例えば、--indexが1の場合、角度は45deg(360deg / 8 * 1)になります。

次に、--x--yを使用して、この角度に基づいてX軸とY軸上の位置を計算します。cos()sin()関数は、角度からX軸とY軸の成分を求めるのに使われます。--xcos(var(--angle))を、--ysin(var(--angle))を使用して、円の中心からの相対的な距離を計算します。

この方法で、各要素を円周上に美しく配置し、動的なデザインを実現することができます。

以下のサンプルコードは三角関数を使って、ドットを配置しています。

以下のような円運動も三角関数を使って実現可能です。

個別の変換プロパティ 〜 transformプロパティで煩わしかった書き味をスッキリと

個別の変換プロパティについて掘り下げてみましょう。これらのプロパティは、ウェブデザインにおける要素の位置、サイズ、回転などを制御するための強力なツールです。

従来、CSSではtransformプロパティを使用して、複数の変換を一つの宣言で指定することが一般的でした。例えば、transform: rotate(45deg) translateX(100px); のように、回転と移動を同時に指定できます。しかし、この方法では、複数の変換を個別に調整するのが難しくなることがあります。

そこで登場するのが、個別の変換プロパティです。これには、translate,rotate,scaleなどがあり、それぞれの変換を個別にコントロールできます。これにより、より細かく、直感的に要素のスタイルを調整できます。

移動(translate):
translateX(value)translateY(value)は、要素を水平方向または垂直方向に移動させます。
例:translateX(100px)は要素を右に100ピクセル移動させます。

回転(rotate):
rotate(value)は、要素を指定された角度で回転させます。
例:rotate(45deg)は要素を45度回転させます。

スケーリング(scale):
scaleX(value)scaleY(value)は、要素の幅または高さを拡大または縮小します。
例:scaleX(2)は要素の幅を2倍にします。

これらの個別の変換プロパティを使うことで、アニメーションやインタラクティブなエフェクトを作成する際に、より精密な制御が可能になります。また、読みやすいコードを書くことができ、メンテナンスやデバッグが容易になります。

今まで以下のように書いていたコードが、

.target {
  transform: translateX(50%) rotate(30deg) scale(1.2);
}

.target:hover {
  transform: translateX(50%) rotate(30deg) scale(2); /* Only scale changed here, yet you have to repeat all other parts */
}

このように書くことができます。

.target {
  translate: 50% 0;
  rotate: 30deg;
  scale: 1.2;
}

.target:hover {
  scale: 2;
}

また従来のtransformプロパティとの主な違いの一つに、宣言した変換が適応される順序です。
transformプロパティを使用すると、変換関数が左から右の順で実行されていきます。
しかし、個々の変換プロパティでは、順序は常に同じで、translaterotatescaleの順に実行されます。

したがって以下のコード例では同じ結果になります。

.transform--individual {
  translate: 50% 0;
  rotate: 30deg;
  scale: 1.2;
}

.transform--individual-alt {
  rotate: 30deg;
  translate: 50% 0;
  scale: 1.2;
}

その他詳細については以下をご覧ください。
https://web.dev/articles/css-individual-transform-properties?hl=ja

ポップオーバー 〜 popover APIを使って今までよりシンプルにポップオーバーを実装

次はポップオーバーです。popover APIを使って今までよりシンプルに実装が可能となりました。

主な特徴は以下のとおりです。

  • トップレイヤーのサポート: z-indexを管理する必要がなくなり、ポップオーバーやダイアログはページの最上部に表示されます。
  • 自動クローズ機能: 要素の外側をクリックすると、ポップオーバーが自動で閉じます。
  • アクセシビリティの向上: ポップオーバーのターゲットとポップオーバー自体がアクセシビリティに対応しています
<div id="event-popup" popover>
  <!-- ここにポップオーバーのコンテンツ -->
</div>
<button popovertarget="event-popup">Create New Event</button>

このコードでは、popover属性を使ってポップオーバーを宣言し、popovertarget属性で関連付けることにより、ボタンクリック時にポップオーバーが表示されます。

こちらにサンプルコードを置いておきます。

アンカーの配置 〜 CSS anchor positioning APIを使ってポップオーバーを柔軟にレイアウト

次はアンカーの配置について見ていきましょう。この機能により、位置決めされた要素(ツールチップやダイアログなど)をポップオーバーした時、ページ上の他の「アンカー要素」に対して位置決めが可能になります。

まずanchor()関数が導入されました。これにより、要素をアンカーの特定の位置に簡単に配置することが可能になります。例えば、次のコードではツールチップをアンカーの上部に配置し、ビューポートに収まらない場合は下部に配置します。

@position-fallback --top-then-bottom {
  @try {
    bottom: calc(anchor(top) + 0.5rem);
    left: anchor(center);
  }

  @try {
    top: calc(anchor(bottom) + 0.5rem);
    left: anchor(center);
  }
}

これを使うには、ツールチップのスタイルにposition-fallbackプロパティを使って指定します。

.center-tooltip {
  position-fallback: --top-then-bottom;
  translate: -50% 0;
}

このように、デザインシステムやライブラリで位置付けのロジックを作成し、どこでも再利用することができます。

以下サンプルコードです。

セレクトメニュー<selectmenu> 〜 従来の<select>タグよりもスタイリングが簡単

次はセレクトメニューです。これにより、従来の<select>タグに比べ、遥かに柔軟なスタイリングが可能になります。

<selectmenu>の基本
<selectmenu>は、<select>と同じように使用しますが、より詳細なスタイリングが可能です。以下の例では、様々なセレクタを使用して、セレクトメニューの各要素をスタイルします:

<selectmenu>
  <button slot="button" behavior="button">
    <span>Select event type</span>
    <span behavior="selected-value" slot="selected-value"></span>
    <span><img src="icon.svg"/></span>
  </button>
  <option value="meeting">
    <figure class="royalblue"></figure>
    <p>Meeting</p>
  </option>
  <option value="break">
    <figure class="gold"></figure>
     <p>Lunch/Break</p>
  </option>
  ...
</selectmenu>

個別のプロパティによるアニメーション 〜 ポップオーバーをアニメーション

次は個別のプロパティ遷移です。これは、Webデザインの構成要素として重要な役割を果たします。

個別のプロパティ遷移とは何か?
個別のプロパティ遷移は、ポップオーバーや選択メニュー、ダイアログなどの要素に滑らかな遷移を提供する技術です。従来、アニメーション化できなかったプロパティ(最上位レイヤやdisplay: noneとの間のアニメーションなど)に対応することで、よりダイナミックで生き生きとしたインタラクションを実現します。

実装の重要性
この機能は、Webページのユーザー体験を向上させるために極めて重要です。ユーザーは、スムーズな遷移と直感的なインタラクションによって、サイトの操作性と快適性を高く評価します。特に、Eコマースサイトやインタラクティブなアプリケーションにおいて、ユーザーエンゲージメントを高める要素となり得ます。

実際の実装では、以下のようにCSSクラスにtransitionプロパティを適用します。

.settings-popover {
  &:popover-open {
    @starting-style {
      transform: translateY(20px);
      opacity: 0;
    }
    transform: translateY(0);
    opacity: 1;
  }
  transform: translateY(-50px);
  opacity: 0;
  transition: transform 0.5s, opacity 0.5s, display 0.5s allow-discrete;
}

このコードでは、オープンの状態を :popover-open、オープン前の状態を @starting-styleを使用して、ポップオーバーをアニメーション化しています。これらすべてをディスプレイで機能させるのに、transitionプロパティに追加して実現しています。

以下サンプルコードです。
Toolbarのボタンを押すと、ポップオーバーをアニメーション表示していることが確認できます。

スクロールドリブンアニメーション 〜 ユーザがスクロールするたびに生き生きと動き出すようなウェブページを作成してみよう

スクロールドリブンアニメーションとは?
スクロールドリブンアニメーションは、スクロールの動きに応じてアニメーションを制御する技術です。これにより、ユーザーがページをスクロールすると、アニメーションが前進または後退するようになります。この技術は、視差効果を持つ背景画像、進行状況バー、ビューに入った時に表示される画像など、様々な視覚効果を生み出すのに役立ちます。

実装方法
スクロールドリブンアニメーションを実装するには、scroll-timelineview-timelineanimation-timelineといった新しいCSSプロパティや、JavaScriptのWeb Animations APIを用いることができます。例えば、ScrollTimelineViewTimelineのインスタンスを Element.animate()timelineオプションとして使用することにより、スクロールに応じたアニメーションが可能になります。

利点と可能性
このAPIは、既存のWeb Animations APIやCSS Animations APIと互換性があり、それらの利点を活用できます。特に、メインスレッド以外でアニメーションを実行する機能は、パフォーマンスの向上に貢献します。数行のコードを追加するだけで、スクロールによって動作する滑らかなアニメーションをメインスレッドで実行できるようになります。

プロパティ 説明 詳細
scroll-timeline スクロール位置に応じてアニメーションを同期させるのに使う https://www.w3.org/TR/scroll-animations-1/#scroll-timelines
view-timeline 要素がビューポート内にあるかどうかに基づいてアニメーションをトリガーするために使う https://www.w3.org/TR/scroll-animations-1/#view-timelines
animation-timeline アニメーションとタイムラインルールを関連付けさせるために使う https://www.w3.org/TR/css-animations-2/#animation-definition

以下は簡単なサンプルコードとスクロールドリブンアニメーションです。
前述のCSSプロパティやJavaScriptのCSS Animations APIで様々なアニメーションを作ることができます。
このようなアニメーションを作るには、それなりの経験と知識が必要そうですが、スクロールに応じてアニメーションが出てくるサイトを作るのはやりがいがありそうですね。

様々なスクロールドリブンアニメーション

以下は、スクロールドリブンアニメーションを活用したウェブページです。

https://scroll-driven-animations.style/

https://ics-creative.github.io/230718_scroll_driven_animations/

ビューのトランジション 〜 View Transition APIを使用して、ビュー遷移をかっこよくしちゃおう

これで最後です。ビューのトランジションです。この機能は、ページの遷移をよりスムーズにし、ユーザー体験を大幅に向上させる可能性を秘めています。

View Transition APIとは
View Transition APIは、DOMを変更する際にスムーズなアニメーションを提供します。これにより、ページ間の遷移だけでなく、ページ内の個別の要素の移動も制御できるようになります。たとえば、あるセクションから別のセクションへのフェードアウトや、要素のスライドなどが可能です。

ビュー遷移の実装は比較的簡単です。以下に基本的な使い方を示します。

function spaNavigate(data) {
  // Fallback for browsers that don't support this API:
  if (!document.startViewTransition) {
    updateTheDOMSomehow(data);
    return;
  }

  // With a transition:
  document.startViewTransition(() => updateTheDOMSomehow(data));
}

このコードは、ビュー遷移APIをサポートしていないブラウザに対するフォールバックも考慮しています。プログレッシブエンハンスメントですね。遷移の見た目はCSSで制御され、以下のようなキーフレームアニメーションを定義できます。

@keyframes slide-from-right {
  from { opacity: 0; transform: translateX(75px); }
}

@keyframes slide-to-left {
  to { opacity: 0; transform: translateX(-75px); }
}

::view-transition-old(root) {
  animation: 350ms both slide-to-left ease;
}

::view-transition-new(root) {
  animation: 350ms both slide-from-right ease;
}

世界一控えめなView Transition APIを使ったサンプルコードです。

まとめ

2024年になって初めての記事なので、楽しんで書きました。そのため紹介の仕方が少し誇張のある表現になっている箇所がありますが、ご了承ください。
いや、まとめようと思ったら、すでに参考にある記事に素晴らしくきれいにまとまっていたので、それに書いていないことを補足するような、また楽しんで読んでもらえるように自分なりに工夫してみました。
参考に載せた記事と並行して読んでもらえると、より理解が深まると思います。

ちなみに僕は辰年です。
やりたいこと、したいことが多すぎで時間が足りないですが、コツコツ地道にやっていこうと思います。
エンジニア界隈のイベントを一緒に盛り上げていきましょう。
2024年もよろしくお願いしまーす!

参考資料

https://developer.chrome.com/blog/whats-new-css-ui-2023

Discussion