モダンCSS概要
近年のCSSは革命的な進化を遂げています。従来JavaScriptが必要だった機能がCSSだけで実装可能になりました。
主な新機能
- Container Queries - 親要素のサイズに応じたスタイル
- :has() - 子要素の存在に基づくスタイル
- Subgrid - 入れ子グリッドの整列
- :is()/:where() - セレクタの簡潔化
- aspect-ratio - アスペクト比の指定
1. Container Queries(コンテナクエリ)
親要素のサイズに応じてスタイルを変更できる画期的な機能です。
従来のメディアクエリの問題
/* 画面幅でしか判定できない */
@media (max-width: 768px) {
.card { font-size: 14px; }
}
/* 問題:カードがサイドバーにある場合も
メイン領域にある場合も同じスタイル */Container Queriesで解決
/* コンテナを定義 */
.sidebar {
container-type: inline-size;
container-name: sidebar;
}
.main {
container-type: inline-size;
container-name: main;
}
/* コンテナのサイズで判定 */
@container (max-width: 400px) {
.card {
font-size: 14px;
padding: 1rem;
}
}
@container (min-width: 600px) {
.card {
font-size: 18px;
padding: 2rem;
display: grid;
grid-template-columns: 1fr 2fr;
}
}実装例
<style>
.container-demo {
container-type: inline-size;
border: 3px solid #2a2a2a;
padding: 1rem;
resize: horizontal;
overflow: auto;
}
.responsive-card {
background: #ffeb3b;
border: 2px solid #000;
padding: 1rem;
}
@container (min-width: 400px) {
.responsive-card {
padding: 2rem;
font-size: 1.2rem;
}
.responsive-card::before {
content: '📱→💻 幅400px以上';
display: block;
font-weight: bold;
margin-bottom: 0.5rem;
}
}
@container (max-width: 399px) {
.responsive-card::before {
content: '📱 幅400px未満';
display: block;
font-weight: bold;
margin-bottom: 0.5rem;
}
}
</style>
<div class="container-demo">
<div class="responsive-card">
このボックスの右下をドラッグしてリサイズ!
</div>
</div>実装結果
📱 Container Queries デモ
(一部ブラウザのみ対応)
このエリアをリサイズすると内容が変化します
(一部ブラウザのみ対応)
このエリアをリサイズすると内容が変化します
container-typeの種類
/* 幅のみ監視(推奨) */
container-type: inline-size;
/* 高さのみ監視 */
container-type: block-size;
/* 幅と高さ両方監視 */
container-type: size;実用例:カードコンポーネント
.card-container {
container-type: inline-size;
}
/* 狭い場合は縦並び */
.card {
display: flex;
flex-direction: column;
}
/* 広い場合は横並び */
@container (min-width: 500px) {
.card {
flex-direction: row;
gap: 2rem;
}
.card-image {
width: 40%;
}
.card-content {
width: 60%;
}
}2. :has() 擬似クラス
「親セレクタ」がついに実現!子要素の存在に応じて親のスタイルを変更できます。
基本構文
/* 画像を含むカードは特別なスタイル */
.card:has(img) {
border: 3px solid #2196f3;
}
/* チェックボックスがチェックされている親 */
.form-group:has(input:checked) {
background: #e8f5e9;
}
/* エラーメッセージがある場合 */
.input-wrapper:has(.error-message) {
border-color: #f44336;
}実装例
<style>
.has-demo-card {
border: 2px solid #ccc;
padding: 1.5rem;
margin: 1rem 0;
transition: all 0.3s;
}
.has-demo-card:has(.highlight) {
border-color: #2196f3;
background: #e3f2fd;
border-width: 3px;
}
</style>
<div class="has-demo-card">
<p>通常のカード</p>
</div>
<div class="has-demo-card">
<p>この中に<span class="highlight">ハイライト</span>があるカード</p>
</div>実装結果
通常のカード
この中にハイライトがあるカード(:has()で検出)
実用例:フォームバリデーション
/* エラーがあるフィールド */
.field:has(.error) {
border-left: 4px solid #f44336;
background: #ffebee;
}
/* 成功状態 */
.field:has(.success) {
border-left: 4px solid #4caf50;
background: #e8f5e9;
}
/* チェックされたラジオボタンの親 */
.option:has(input[type="radio"]:checked) {
background: #2196f3;
color: white;
font-weight: bold;
}兄弟要素の制御
/* ホバーしている要素以外を薄く */
.gallery:has(.item:hover) .item:not(:hover) {
opacity: 0.5;
}
/* フォーカスがある場合、ラベルを強調 */
form:has(input:focus) label {
color: #2196f3;
font-weight: bold;
}3. Subgrid
グリッドアイテムの中でも親グリッドの線を共有できます。
従来の問題
/* 親グリッド */
.grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}
/* 子要素内のグリッドは独立 */
.grid-item {
display: grid;
grid-template-columns: 1fr 1fr; /* 親と揃わない */
}Subgridで解決
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
.grid-item {
display: grid;
grid-column: span 3;
grid-template-columns: subgrid; /* 親のグリッドを継承 */
}実装例
<style>
.subgrid-demo {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
border: 3px solid #2a2a2a;
padding: 1rem;
}
.subgrid-item {
background: #ffeb3b;
border: 2px solid #000;
padding: 1rem;
display: grid;
grid-column: span 3;
grid-template-columns: subgrid;
gap: 1rem;
}
.subgrid-child {
background: white;
border: 2px solid #2196f3;
padding: 0.5rem;
text-align: center;
}
</style>
<div class="subgrid-demo">
<div style="background: #e0e0e0; padding: 1rem;">Col 1</div>
<div style="background: #e0e0e0; padding: 1rem;">Col 2</div>
<div style="background: #e0e0e0; padding: 1rem;">Col 3</div>
<div class="subgrid-item">
<div class="subgrid-child">A</div>
<div class="subgrid-child">B</div>
<div class="subgrid-child">C</div>
</div>
</div>実装結果(対応ブラウザのみ)
Subgridデモ(Firefox/Safari対応)
Col 1
Col 2
Col 3
A
B
C
4. :is() と :where()
セレクタを簡潔に書ける便利な擬似クラスです。
:is() - セレクタリストの簡潔化
/* 従来 */
h1 a:hover,
h2 a:hover,
h3 a:hover {
color: #2196f3;
}
/* :is()で簡潔に */
:is(h1, h2, h3) a:hover {
color: #2196f3;
}:where() - 詳細度0
/* :is()は最も高い詳細度を持つ */
:is(#id, .class) { } /* 詳細度: 1,0,0 */
/* :where()は常に詳細度0 */
:where(#id, .class) { } /* 詳細度: 0,0,0 */
/* 上書きしやすいデフォルトスタイルに便利 */
:where(button, .btn) {
padding: 0.5rem 1rem;
border: none;
}
/* 簡単に上書き */
.btn-large {
padding: 1rem 2rem;
}実用例
/* フォーム要素のまとめ */
:is(input, textarea, select):focus {
outline: 2px solid #2196f3;
outline-offset: 2px;
}
/* 見出しのまとめ */
:is(h1, h2, h3, h4, h5, h6) {
font-weight: bold;
line-height: 1.2;
margin-bottom: 1rem;
}
/* ネガティブマージン除外 */
:is(article, section) > :where(h2, h3):first-child {
margin-top: 0;
}5. aspect-ratio
アスペクト比を直接指定できます。
従来のpadding-topトリック
/* 16:9の比率を保つ */
.video-wrapper {
position: relative;
padding-top: 56.25%; /* 9/16 * 100 */
}
.video-wrapper iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}aspect-ratioで簡単に
.video-wrapper {
aspect-ratio: 16 / 9;
}
.video-wrapper iframe {
width: 100%;
height: 100%;
}
/* その他の例 */
.square { aspect-ratio: 1; }
.photo { aspect-ratio: 4 / 3; }
.portrait { aspect-ratio: 2 / 3; }実装結果
1:1
正方形
正方形
16:9
動画
動画
4:3
写真
写真
6. accent-color
フォーム部品の色を一括変更できます。
使い方
/* チェックボックス、ラジオボタン、レンジなど */
input[type="checkbox"],
input[type="radio"],
input[type="range"] {
accent-color: #2196f3;
}
/* 全体に適用 */
:root {
accent-color: #4caf50;
}実装結果
7. ブラウザ対応状況
Container Queries:
✅ Chrome 105+
✅ Edge 105+
✅ Safari 16+
✅ Firefox 110+
:has():
✅ Chrome 105+
✅ Edge 105+
✅ Safari 15.4+
✅ Firefox 121+
Subgrid:
✅ Firefox 71+
✅ Safari 16+
✅ Chrome 117+
✅ Edge 117+
:is()/:where():
✅ すべてのモダンブラウザ
aspect-ratio:
✅ すべてのモダンブラウザ
accent-color:
✅ Chrome 93+
✅ Edge 93+
✅ Firefox 92+
✅ Safari 15.4+8. 実践的な組み合わせ例
レスポンシブカードグリッド
.grid {
container-type: inline-size;
display: grid;
gap: 1rem;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
.card {
aspect-ratio: 1;
display: grid;
place-items: center;
}
/* 親が狭い場合 */
@container (max-width: 600px) {
.card {
aspect-ratio: 16 / 9;
}
}
/* 画像を含むカードは特別なスタイル */
.card:has(img) {
aspect-ratio: 4 / 3;
background: linear-gradient(135deg, #667eea, #764ba2);
}インタラクティブフォーム
/* アクセントカラー設定 */
:root {
accent-color: #2196f3;
}
/* エラーがあるフィールド */
.field:has(.error) {
border-left: 4px solid #f44336;
}
/* チェックされたオプション */
.option:has(input:checked) {
background: #e3f2fd;
border-color: #2196f3;
}
/* フォーカス時のラベル */
:is(.field, .option):has(:focus) label {
color: #2196f3;
font-weight: bold;
}まとめ
モダンCSSで開発が劇的に効率化します!
主なメリット
- ✅ JavaScriptが不要になるケースが増加
- ✅ より直感的で保守しやすいコード
- ✅ パフォーマンス向上
- ✅ アクセシビリティ改善
学習の優先順位
- :has() - すぐに使える、効果大
- aspect-ratio - 頻繁に使う
- :is()/:where() - コード簡潔化
- Container Queries - 複雑だが強力
- Subgrid - 特定用途向け
今すぐ試そう
- 既存のpadding-topトリックをaspect-ratioに置換
- メディアクエリをContainer Queriesに移行検討
- :has()でJavaScriptの条件分岐を削減
- フォーム部品にaccent-colorを適用