「この見た目を実現するために、なぜここまでSassやJavaScriptを使わないといけないんだろう」——フロントエンドの実装をしていると、そんな違和感を覚えることはないでしょうか。親要素の状態に応じてスタイルを変えたい、コンポーネント単位でレスポンシブにしたい、といった要望は、これまでCSSだけでは対応が難しい場面が多くありました。
実はここ数年で、CSSにはそうした「面倒だった実装」を素のCSSだけで解決できる機能が次々と追加されています。この記事では、実際にフロントエンド開発の現場で使い始められている新しいCSS機能を取り上げ、何が便利になったのか、使ってみてどう感じるかを具体的なコード例とあわせて紹介します。
この記事のポイント
- CSSのネイティブネストで、プリプロセッサなしでも入れ子記法が書けるようになった
- :has()やコンテナクエリなど、これまでJavaScriptに頼っていた処理をCSSだけで実現できる場面が増えた
- 導入前に確認しておきたいブラウザ対応状況のチェックポイントも解説
なぜ今、CSSの新機能に注目すべきなのか
CSSは長らく「できることが限られている言語」という印象を持たれてきました。そのため、複雑なレイアウトや条件分岐が必要な表現は、SassやLessといったプリプロセッサ、あるいはJavaScriptによるクラス切り替えで補うのが一般的でした。
しかし近年、主要ブラウザの実装が進んだことで、こうした課題をCSSの標準機能だけで解決できるケースが増えています。結果として、ビルド環境への依存を減らしたり、コード量そのものを減らしたりできる場面が出てきました。ここからは、特に「実装が簡単になった」と感じる機能を順番に見ていきます。
1. ネイティブCSSネスト(入れ子記法)
これまでCSSで入れ子のセレクタを書くには、Sassなどのプリプロセッサを導入するのが一般的でした。今は、ビルドツールを使わなくても、CSSファイルの中に直接ネストした記法を書けるようになっています。
.card {
padding: 16px;
border-radius: 8px;
&:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.card-title {
font-size: 1.2rem;
font-weight: bold;
}
}
子要素のスタイルを外側のブロック内にまとめて書けるため、コンポーネント単位でCSSファイルを整理しやすくなります。子孫セレクタの前には&を省略できる書き方も用意されていますが、可読性を重視して明示的に書くチームも多いようです。プリプロセッサをすでに使っているプロジェクトであれば、無理に置き換える必要はありませんが、新規プロジェクトでは「まずは素のCSSで書いてみる」という選択肢が現実的になりました。
2. :has()による親要素・条件付きセレクタ
「この子要素があるときだけ、親要素の見た目を変えたい」という要望は、これまでJavaScriptでクラスを付け外しする以外に方法がありませんでした。:has()を使うと、この処理をCSSのセレクタだけで表現できます。
/* 画像を含むカードだけ枠線を太くする */
.card:has(img) {
border-width: 2px;
}
/* チェックボックスがオンのときに、隣接するラベルの文字色を変える */
input:checked + label {
color: #007bff;
}
/* フォーム内に無効な入力があるときだけ、送信ボタンを目立たせる */
form:has(:invalid) button[type="submit"] {
opacity: 0.6;
}
フォームのバリデーション表示や、記事内に画像がある場合だけレイアウトを変える、といった「条件によって親の見た目を変える」処理を、JavaScriptを書かずに実装できるようになった点は、実務でも恩恵を感じやすい部分です。
3. コンテナクエリで「コンポーネント単位」のレスポンシブ対応
従来のメディアクエリは、画面全体の幅を基準にスタイルを切り替える仕組みでした。しかし実際のUIでは、同じカードコンポーネントでもサイドバーに置かれるか、メインカラムに置かれるかによって、最適な見た目が変わることがあります。
コンテナクエリを使うと、コンポーネントが置かれている「親要素の幅」を基準にスタイルを切り替えられます。
.card-container {
container-type: inline-size;
}
.card {
display: block;
}
/* コンテナの幅が400px以上のときだけ横並びにする */
@container (min-width: 400px) {
.card {
display: flex;
align-items: center;
gap: 16px;
}
}
これにより、同じコンポーネントを画面のどこに配置しても、その場所の幅に応じて自然にレイアウトが調整されます。再利用可能なコンポーネント設計と相性がよく、デザインシステムを運用しているプロジェクトでは特に効果を感じやすい機能です。
4. カスケードレイヤー(@layer)で優先順位を整理する
CSSが肥大化してくると、「なぜこのスタイルが効かないのか」という詳細度(specificity)の問題に悩まされることが増えます。@layerを使うと、スタイルの適用順序をレイヤーという単位で明示的に管理できます。
@layer reset, base, components, utilities;
@layer reset {
* { margin: 0; padding: 0; }
}
@layer components {
.button { padding: 8px 16px; border-radius: 4px; }
}
@layer utilities {
.text-center { text-align: center; }
}
先に宣言したレイヤーほど優先度が低くなるため、「utilitiesクラスは常にcomponentsより優先したい」といったルールを、セレクタの詳細度を無理に調整することなく実現できます。特にリセットCSS、共通コンポーネント、ページ固有のスタイルが混在する大規模なプロジェクトで効果を発揮します。
5. text-wrap: balanceで見出しの改行が整う
見出しの折り返し位置がバラバラで、1行だけ極端に短い、または長い状態になってしまうことがあります。これまではJavaScriptで文字数を調整するか、手動で改行タグを入れるしかありませんでした。text-wrap: balanceを指定すると、複数行になったときの各行の長さをブラウザが自動的に整えてくれます。
h1, h2 {
text-wrap: balance;
}
1行で終わる短いテキストには影響しないため、見出しやキャッチコピーに指定しておくだけで見た目の整いが自然に改善されます。CSS1行で完結する手軽さも魅力です。
6. light-dark()とcolor-mix()で色の扱いが簡単に
ダークモード対応では、これまでライト用とダーク用の色をそれぞれ変数として定義し、メディアクエリで切り替えるのが一般的でした。light-dark()関数を使うと、1つの記述の中でライト・ダーク両方の色を指定できます。
:root {
color-scheme: light dark;
}
body {
background-color: light-dark(#ffffff, #1a1a1a);
color: light-dark(#222222, #eeeeee);
}
また、color-mix()を使うと、既存の色を混ぜて新しい色をCSS上で直接生成できます。ホバー時に少し色を濃くする、といった調整のためだけにデザインツールを開く必要がなくなります。
.button:hover {
background-color: color-mix(in srgb, #007bff 80%, black);
}
結局、何がどれくらい簡単になったのか
ここまで紹介した機能について、従来のやり方と比べたときの変化を整理すると、次のようになります。
| 機能 | これまでの主な代替手段 | 簡単になった点 |
|---|---|---|
| CSSネスト | Sass等のプリプロセッサ | ビルド環境なしで入れ子記法が書ける |
| :has() | JavaScriptでのクラス切り替え | 条件分岐をセレクタだけで表現できる |
| コンテナクエリ | 画面幅基準のメディアクエリ | コンポーネント単位でレスポンシブにできる |
| @layer | 詳細度の調整・!important | 適用順序を明示的に管理できる |
| text-wrap: balance | JavaScriptによる改行調整 | CSS1行で見出しの折り返しが整う |
| light-dark() / color-mix() | 複数の色変数を個別に管理 | 1つの記述で配色や色調整ができる |
導入前に確認しておきたいこと
便利な機能である一方、ブラウザの対応状況はプロジェクトが対象とする利用環境によって確認が欠かせません。導入前に、以下のポイントをチェックしておくと安心です。
- 案件やサービスが対象とするブラウザ・バージョンで、使いたい機能が利用できるか「Can I use」などの最新情報で確認する
- 対象外のブラウザが残る場合は、フォールバック用のスタイルや
@supportsによる条件分岐を用意する - 既存のプリプロセッサ環境と機能が重複しないか、チーム内でルールをすり合わせる
- 本番リリース前に、主要なブラウザで実際の表示を目視確認する
特にコンテナクエリや:has()のように比較的新しい機能は、対応状況が今も更新され続けています。記事執筆時点の情報を鵜呑みにせず、実装のタイミングで公式のブラウザ対応表を確認することをおすすめします。
まとめ
CSSネスト、:has()、コンテナクエリ、@layer、text-wrap: balance、light-dark()やcolor-mix()といった機能により、これまでプリプロセッサやJavaScriptに頼っていた処理の一部を、素のCSSだけで実装できる場面が増えています。特に条件付きのスタイル切り替えや、コンポーネント単位のレスポンシブ対応は、実装の見通しが立てやすくなったと感じるポイントです。
まずは自分が携わっているプロジェクトの対象ブラウザを確認したうえで、小さなコンポーネントから試験的に取り入れてみることをおすすめします。既存のコードをすべて置き換える必要はなく、新しく書く部分から少しずつ活用していくことで、無理なく実装を効率化できます。

0 件のコメント:
コメントを投稿