2024年に追加された中で最も使用されたCSSの新機能トップ5とワースト5まとめ

今年も残り1ヶ月を切りました。

月日が経つのは早いものですが、CSSの進化も早く、今年は50以上の機能が追加されました。

## State of CSS 2024

2024年のCSSの現状調査を行った結果をまとめた「[State of CSS 2024](https://2024.stateofcss.com/)」を紹介します。
State of CSS 2024とは、[State of CSS](https://stateofcss.com/)で行われたアンケートの2024年バージョンです。

そのアンケートの中に、2024年に追加されたCSSの新機能それぞれに

* 知らない
* 知っている
* 使ったことがある

のいずれかを回答してもらうというものがあり、それらをまとめたものが[State of CSS 2024: Features](https://2024.stateofcss.com/en-US/features/#all_features)です。

全部で60個もありますが、どの機能が最も使われていて、どの機能が全然使われていない（もしくは知られていない）かが一目瞭然です。

まずはそのランキングを発表し、トップ5とワースト5について、詳細にその機能を見ていきたいと思います。

## ランキング

1. CSS Filter Effects
1. `:has()`
1. Intrinsinc Sizing Keywords
1. `aspect-ratio`
1. `scroll-behavior`
1. CSS Comparison Functions
1. `backdrop-filter`
1. `:focus-visible`
1. CSS Nesting
1. `prefers-color-scheme`
1. Small, Large, and Dynamic Viewport Units
1. `line-clamp`
1. `prefers-reduced-motion`
1. `font-display`
1. `@supports`
1. Blend Modes
1. CSS Logical Properties
1. Scroll Snap
1. `text-wrap: balance`
1. `:where()`
1. Variable Fonts
1. `@container size queries`
1. `linear()` Easing Function
1. `color-scheme`
1. `accent-color`
1. `overscroll-behavior`
1. Subgrid
1. Media Queries Range Contexts
1. `text-wrap: pretty`
1. `conic-gradient()`
1. `image()`
1. `scrollbar-gutter`
1. Cascade Layers
1. `image-set()`
1. CSS Writing Modes
1. `color-mix()`
1. `nth-child of S`
1. Trigonometric Functions
1. `@property`
1. Relative Colors
1. Wide Gamut Colors
1. Interpolation Color Spaces
1. ViewTransition API
1. Discrete Properties Animations
1. `light-dark()`
1. `initial-letter`
1. `color()`
1. `prefers-contrast`
1. `scroll-timeline`
1. `@container style queries`
1. Stepped Value Functions
1. `@scope`
1. `offset-path`
1. Anchor Positioning
1. Exponential Functions
1. Sign-Related Functions
1. `prefers-reduced-data`
1. `view-timeline`
1. `forced-colors`
1. `hanging-punctuation`

皆さんはいくつ知っていました（もしくは使ったことがありました）か？

## トップ5

まずはトップ5から見ていきましょう。

全体的に使用頻度が高い機能なので、皆さんも使ったことや知っている機能が多いと思います。

### 5位: `scroll-behavior`

まず5位は`scroll-behavior`です。

ページ内リンクなどでスクロールの動きをスムーズにするプロパティですね。

今まではJavaScriptでスクロールしたい対象までの座標を取得して`window.scroll`メソッドで設定していましたが、このプロパティを指定すればそれだけでスムーススクロールが実現します。

<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="zxOxWGa" data-pen-title="Qiita: State of CSS 2024 Rank 5th Scroll Behavior" data-user="yoruaki" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/yoruaki/pen/zxOxWGa">
  Qiita: State of CSS 2024 Rank 5th Scroll Behavior</a> by Yoruaki (<a href="https://codepen.io/yoruaki">@yoruaki</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

私もよく使っています。

固定ヘッダーなどがある場合は、`scroll-margin-top`なども併用するといいですね。

### 4位: `aspect-ratio`

4位は`aspect-ratio`です。

指定されたアスペクト比を保ったまま拡大・縮小してくれるプロパティです。

以下は16:9のアスペクト比で画像を3つ並べたサンプルです。

<p class="codepen" data-height="600" data-default-tab="result" data-slug-hash="emONGPv" data-pen-title="Qiita: State of CSS 2024 Rank 4th Aspect Ratio" data-user="yoruaki" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/yoruaki/pen/emONGPv">
  Qiita: State of CSS 2024 Rank 4th Aspect Ratio</a> by Yoruaki (<a href="https://codepen.io/yoruaki">@yoruaki</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

画像自体は指定するアスペクト比になっていない場合が多いので、別途`object-fit`などで要素内にどのように表示させるか指定してあげるとよいでしょう。

### 🥉3位: Intrinsinc Sizing Keywords

3位はサイズに関する`min-content`、`max-content`、`fit-content`のキーワードでした。

個人的にはこの`fit-content`が使用頻度第1位で、公私ともによく使っていた記憶があります。

<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="VYZLbOV" data-pen-title="Qiita: State of CSS 2024 Rank 3rd Intrinsic Sizing Keywords" data-user="yoruaki" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/yoruaki/pen/VYZLbOV">
  Qiita: State of CSS 2024 Rank 3rd Intrinsic Sizing Keywords</a> by Yoruaki (<a href="https://codepen.io/yoruaki">@yoruaki</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

上記のサンプルは、2番目以降の段落に`width: fit-content;`を指定しています。

さすがにこのサンプルだとシンプルすぎて分かりにくいかもですが、要素のサイズをその要素自身にフィットした大きさにしたい、という場面はままあると思います。

### 🥈2位: `:has()`

2位は`:has()`です。

この擬似クラス関数の登場に、多くのフロントエンドエンジニアが歓喜したことでしょう。  
主にチェックボックス関連の実装で、その便利さを実感できます。

#### :has()がない時代の課題

以下のようなチェックボックスのHTMLを考えてみます。

```html
<label>
    <input type="checkbox">チェックボックス
</label>
```

これまで、`input`要素がチェックされたかどうかを、親要素である`label`が知る術がありませんでした。
また、`input`は空要素のため、チェック状態を子要素に伝えることもできません。

結果として、以下のように兄弟要素の状態を利用してスタイルを調整する構成が一般的でした。

```html:HTML
<div>
    <input type="checkbox" id="example">
    <label for="example">チェックボックス</label>
</div>
```

```css:CSS
label {
    cursor: pointer;
}

input:checked + label {
    background-color: palegreen;
}
```

このような方法ではHTMLの構成に依存するため、柔軟性に欠ける実装となりがちです。
あるいは、JavaScriptを利用して親要素に`class`属性（例えば`isChecked`など）を付与するなど、別途の工夫が必要でした。

#### `:has()`の登場で実現した柔軟な実装

`:has()`の登場により、親要素が子要素の状態を直接参照できるようになり、HTMLの構成や実装パターンにおける選択肢が大幅に広がりました。

```css:CSS
label:has(:checked) {
    background-color: palegreen;
}
```

これにより、JavaScriptを用いた`class`属性の付与や、構成の制約を気にする必要がなくなります。

<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="NPKqgxr" data-pen-title="Qiita: State of CSS 2024 Rank 2nd Has Selector" data-user="yoruaki" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;"> <span>See the Pen <a href="https://codepen.io/yoruaki/pen/NPKqgxr"> Qiita: State of CSS 2024 Rank 2nd Has Selector</a> by Yoruaki (<a href="https://codepen.io/yoruaki">@yoruaki</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p>

フォーム関連はJavaScriptや他の言語と絡むことも多いので、スタイルに関してはなるべくシンプルな構成にしたほうが、見通しも良くなってその後の修正やリファクタもやりやすくなると思います。

### 🥇1位: CSS Filter Effects

堂々の第1位は、Filter Effectsでした！
これは`filter`プロパティで使われる`blur()`や`contrast()`のことで、画像、背景、境界の描画を調整するためによく使われます。

<p class="codepen" data-height="600" data-default-tab="result" data-slug-hash="ogvXyMd" data-pen-title="Untitled" data-user="yoruaki" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/yoruaki/pen/ogvXyMd">
  Untitled</a> by Yoruaki (<a href="https://codepen.io/yoruaki">@yoruaki</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

これらのキーワードが使える`backdrop-filter`プロパティも、7位にランクインしてますね。

## ワースト5

ワースト5というと、ちょっと悪い印象になりますね…。

改めまして、最も使用頻度の低い（もしくは知られていない）新機能トップ5を見ていきましょう。

ここから先は未知の領域で、ここに登場する5つの新機能は、私はすべて知りませんでした😇

### 56位: Sign-Related Functions

56位は`sign()`関数でした。

`sign()`関数は、引数の正負を表す符号関数です。

引数の結果が正だったら`1`、負だったら`-1`、0だったら`0`（`+0` or `-0`）、それ以外だったら`NaN`を返します。

引数には`calc()`や`clamp()`などの数学関数や数式が使えます。

```css:CSS
/* 正なので 1 を返す = margin-top: 20px; */
.example1 {
    margin-top: calc(sign(10px + 20px) * 20px; 
}

/* 負なので -1 を返す = margin-top: -20px; */
.example2 {
    margin-top: calc(sign(10px - 20px) * 20px; 
}

/* ゼロなので 0 を返す = margin-top: 0px; */
.example1 {
    margin-top: calc(sign(10px - 10px) * 20px; 
}
```

以下サンプルです。

ボタンで1emのサイズを1pxずつ増減してみてください。
計算結果（`1em - 16px`）の差分が正なら右に20px、負なら左に20px、ゼロなら中央に移動します。

:::note
2024年12月9日現在、SafariとFirefoxが対応しています
:::


<p class="codepen" data-height="450" data-default-tab="css,result" data-slug-hash="ByByOpr" data-pen-title="Untitled" data-user="yoruaki" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/yoruaki/pen/ByByOpr">
  Untitled</a> by Yoruaki (<a href="https://codepen.io/yoruaki">@yoruaki</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

CSSではゼロは`0`なので、positive zeroとnegative zeroという概念があることを初めて知りました。

### 57位: `prefers-reduced-data`

ユーザーがページのレンダリングに使われるデータ通信量が、より少ない代替コンテンツを提供することをリクエストしているかどうかを検出するメディア特性です。

とりあえずデータ通信量を減らしたいユーザーがいたら、それに合わせて表示や読み込むデータを変える、みたいな使い方ができます。

```css:CSS
.image {
    background-image: url("images/heavy.jpg");
}

@media (prefers-reduced-data: reduce) {
    /* Save-Data: On */
    .image {
        background-image: url("images/light.jpg");
    }
}
```

[サンプルコード](https://www.w3.org/TR/mediaqueries-5/#example-b1599633)では、データ通信量を減らす設定になっているとき（`prefers-reduced-data: reduce`）は`images/light.jpg`を読み込み、それ以外は`images/heavy.jpg`を読み込みます。

ちなみに`no-preference`は何も設定されていない状態です。

以下のサンプルでは、何も設定がされていない場合、赤い四角が表示されます。

データ通信量を減らす設定にしている（HTTPヘッダーの[Sava-Data](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Save-Data)がOnになっている）場合、青い四角が表示されます。

<p class="codepen" data-height="300" data-default-tab="result" data-slug-hash="vEBEaqX" data-pen-title="Qiita: State of CSS 2024 Rank 57th Prefers Reduced Data" data-user="yoruaki" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/yoruaki/pen/vEBEaqX">
  Qiita: State of CSS 2024 Rank 57th Prefers Reduced Data</a> by Yoruaki (<a href="https://codepen.io/yoruaki">@yoruaki</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

まぁサンプルを置いたはいいですが、2024年12月9日現在[どのブラウザも対応していません](https://caniuse.com/mdn-css_at-rules_media_prefers-reduced-data)。

![2024年12月9日時点のCan I use（`prefers-reduced-data`）のキャプチャ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45505/3bf2b08b-43df-ab51-2700-a02f4447ace4.png)

https://developer.mozilla.org/docs/Web/CSS/@media/prefers-reduced-data

### 🤔58位: `view-timeline`

`view-timeline`は、スクロールに基づくアニメーションをタイムラインとして制御するためのプロパティです。

このタイムラインは、対象となるスクロール可能な要素が初期位置に表示されると`0%`となり、反対側の端に達すると`100%`になります。

`view-timeline`は一括指定プロパティで、他に`view-timeline-name`と`view-timeline-axis`があります。

`view-timeline-name`はタイムラインに名前をつけます。初期値は`none`なので特に考えなくてもいいです。

`view-timeline-axis`はスクロールバーの方向を指定するために使用します。
`block`は縦方向、`inline`は横方向です。

以下のサンプルは、スクロールの進行に応じて赤い四角から大きい青い四角にアニメーションします。

<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="pvzvYdp" data-pen-title="Qiita: State of CSS 2024 Rank 58th View Timeline" data-user="yoruaki" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/yoruaki/pen/pvzvYdp">
  Qiita: State of CSS 2024 Rank 58th View Timeline</a> by Yoruaki (<a href="https://codepen.io/yoruaki">@yoruaki</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

スクロールに基づくアニメーションをコントロールできるため、ユーザーがページを移動する際に視覚的な変化をもたらし、インタラクティブ性を向上させることができるかもしれませんね。

### 😨59位: `forced-colors`

ユーザーエージェントが強制カラーモードを有効にしているかどうかを検出するためのメディア特性です。

強制カラーモードの例としては、Windowsのハイコントラストモードがあります。

ここで注意したいのが、この強制カラーモードには、いわゆる「ライトモード」や「ダークモード」は含まれないということです。そっちは[`prefers-color-scheme`](https://developer.mozilla.org/docs/Web/CSS/@media/prefers-color-scheme)を使いましょう。

ではそんな`prefers-color-scheme`との使い分けですが、以下のような場合が考えられます。

> 例えば、`border: none`のスタイルをあてたボタンがあった場合、それぞれライト・ダークモードでは見えていたボタンと背景の境界が、強制カラーモードだと見えなくなってしまいます。
> via: [強制カラーモードに対するメディアクエリforced-colorsの使い方](https://www.mitsue.co.jp/knowledge/blog/frontend/202405/17_1401.html)

そんなときに、強制カラーモード時に`border`を指定してあげるという使い方があります。

```css:CSS
@media (forced-colors: active) {
    button {
        border-width: 3px;
        border-style: dashed;
    }
}
```

以下のサンプルを、強制カラーモードにして確認してみてください。
デフォルトボタンはボタンと背景の境界が分からなくなってしまいますが、対応ボタンは太さ3px、dashedスタイルのボーダーが表示され、ボタンを認識できるかと思います。

Mac環境の人は、[Edgeの開発者ツールで`forced-color: active`のシミュレーションができます](https://christianheilmann.com/2023/04/28/microsoft-edge-now-allows-you-to-simulate-dark-light-high-contrast-mode-blurred-vision-and-colour-deficiencies-right-from-the-device-emulation-toolbar/)。

<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="gbYpvEJ" data-pen-title="Untitled" data-user="yoruaki" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/yoruaki/pen/gbYpvEJ">
  Untitled</a> by Yoruaki (<a href="https://codepen.io/yoruaki">@yoruaki</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

一応こんな表示になります。

![強制カラーモード時の表示](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45505/f95ef21a-57fe-546f-41be-03f4217520a3.png)


いろいろ調べてみたのですが、現状ハイコントラストモードはWindowsにしかなく、MacやAndroidなどでもアクセシビリティ観点で似た機能はありつつも、ライトモード、ダークモード含め`forced-color`に影響を与えるものではないため、使い所が限定的だなと感じました。

### 😱60位: `hanging-punctuation`

最も使用頻度の低かった新機能第1位は、`hanging-punctuation`でした！
それもそのはず、回答者の実に84.7%の人が聞いたこともないと回答しています。
かくいう私も全然聞いたこともなかったです。

直訳すると「ぶら下がり句読点」ですが、まず、ウェブの文章には行頭に句読点が来ないようにする禁則処理というものがあります。

例えば『[Qiitaの思想](https://qiita.com/about)』より以下の文章。

```text
Qiitaはエンジニアにとって
再利用性・汎用性の高い他の
ユーザーにとっても役にたつ
、学びのある情報が多く集ま　←　ここ
っている場であり続けたいと
考えています。
```

禁則処理が行われると以下のようになります。

```text
Qiitaはエンジニアにとって
再利用性・汎用性の高い他の
ユーザーにとっても役にた　　←　ここ
つ、学びのある情報が多く集
まっている場であり続けたい
と考えています。
```

今回の機能は、上記のように直前の文字を改行することで行頭に句読点などの禁則文字が来るのを防ぐのではなく、直前の行の最後に句読点を持っていきます。

```text
Qiitaはエンジニアにとって
再利用性・汎用性の高い他の
ユーザーにとっても役にたつ、　←　ここ
学びのある情報が多く集まっ
ている場であり続けたいと考
えています。
```

これを「ぶら下げ組み」というそうです。

https://ja.wikipedia.org/wiki/%E3%81%B6%E3%82%89%E4%B8%8B%E3%81%92%E7%B5%84%E3%81%BF

で、それを実現するのが`force-end`という値です。

以下にサンプルを置いておきます。1番目の段落は普通の`p`要素です。横幅を変えれば普通に禁則処理が走ります。

2番目の段落には

```css:CSS
p {
    hanging-punctuation: force-end;
}
```

を指定しています。
横幅を変えると、1番目の段落とは違った動きになると思います。

:::note
2024年12月9日現在、Safariのみ対応しています。
:::

![2024年12月9日時点のCan I use（`hanging-punctuation`）のキャプチャ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45505/8067263b-6cdb-2e1f-6487-9059f319034e.png)

https://caniuse.com/css-hanging-punctuation

<p class="codepen" data-height="600" data-default-tab="result" data-slug-hash="zxOYpyZ" data-pen-title="Qiita: State of CSS 2024 Rank 60th Hanging Punctuation" data-user="yoruaki" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/yoruaki/pen/zxOYpyZ">
  Qiita: State of CSS 2024 Rank 60th Hanging Punctuation</a> by Yoruaki (<a href="https://codepen.io/yoruaki">@yoruaki</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

一応こんな感じの動きになります。

![「ぶら下げ組み」の例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45505/38f66c54-10f7-040b-02cd-e403af4fffa8.png)

参考: [CSSでの句読点ぶら下げ: hanging-punctuationプロパティ](https://techracho.bpsinc.jp/baba/2017_07_31/43953)

## まとめ

2024年に追加された中で最も使用されたCSSの新機能トップ5とワースト5をまとめてみました。

皆さんはどの機能をすでに使っていますか？
もしくは初めて知った新機能はありましたか？

CSSの進化は早く、次々に新しい機能が登場していますが、すべてをキャッチアップする必要はなく、適材適所で便利な部分は使いつつも、大切なのはユーザーにどんな価値を提供できるかだと思っています。

新しい機能に歓喜したり困惑したりしつつ、来年も素晴らしいサイトの実装に邁進していきましょう。

最後になりますが、この記事を書くにあたって、特にワースト5のまとめを書くのが調査も含めて一番時間がかかりました😂

これまでに情報を調べてウェブに残してくれた先人たちに感謝します。