疑問
モダンなCSSの機能を効果的に活用するには、どのようなテクニックがあるのでしょうか?Grid、Flexbox、CSS変数などの実践的な使い方を一緒に学んでいきましょう。
導入
CSSは年々進化を続けており、CSS Grid、Flexbox、CSS変数、コンテナクエリなど、強力な機能が追加されています。これらのモダンなCSS機能を活用することで、より効率的で保守しやすいスタイルシートを書くことができます。
本記事では、モダンなCSSの主要な機能と、実践的な使い方を詳しく解説します。レイアウト、アニメーション、レスポンシブデザインなど、様々な場面での活用方法を紹介していきます。
解説
1. CSS Gridの活用
CSS Gridは、2次元のレイアウトを実装できる強力な機能です。行と列の両方を制御でき、複雑なレイアウトを簡単に実現できます。Flexboxが1次元(行または列)のレイアウトに適しているのに対し、Gridは2次元(行と列)のレイアウトに適しています。
基本的なGridレイアウト
CSS Gridの基本的な使い方:
グリッドコンテナの設定:
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: auto;
gap: 1rem;
}主なプロパティ:
-
display: grid: Gridを有効化-
grid-template-columns: 列の定義(repeat(3, 1fr)は3列を均等に)-
grid-template-rows: 行の定義-
gap: グリッドアイテム間の間隔(row-gapとcolumn-gapのショートハンド)グリッドアイテムの配置:
-
grid-column: 列の位置(span 2で2列分)-
grid-row: 行の位置-
grid-area: エリア名を指定複雑なレイアウト
Gridを使用して複雑なレイアウトを実現する方法:
グリッドエリアの使用:
.layout {
display: grid;
grid-template-areas:
"header header header"
"sidebar main main"
"footer footer footer";
grid-template-columns: 200px 1fr 1fr;
grid-template-rows: auto 1fr auto;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }自動配置の活用:
-
grid-auto-flow: row(デフォルト): 行方向に自動配置-
grid-auto-flow: column: 列方向に自動配置-
grid-auto-flow: dense: 隙間を埋めるように配置minmax()の使用:
.grid {
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}これにより、最小幅300pxで自動的に列数が調整されます。
Gridの高度な機能
Gridの高度な機能:
サブグリッド(Subgrid):
親のグリッドラインを継承(ブラウザサポートが限定的)
.item {
display: grid;
grid-template-columns: subgrid;
}グリッドラインの名前付け:
.grid {
grid-template-columns: [start] 1fr [middle] 1fr [end];
}
.item {
grid-column: start / end;
}アライメント:
-
justify-items: グリッドアイテムの水平方向の配置-
align-items: グリッドアイテムの垂直方向の配置-
place-items: 両方のショートハンド-
justify-content: グリッド全体の水平方向の配置-
align-content: グリッド全体の垂直方向の配置CSS Gridの実装例
基本的なGridレイアウトから複雑なレイアウトまでの実装例です。
/* 基本的なGridレイアウト */
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 2rem;
padding: 2rem;
}
.grid-item {
background-color: #f0f0f0;
padding: 1.5rem;
border-radius: 8px;
}
/* レスポンシブなGrid */
.responsive-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 1.5rem;
}
/* 複雑なレイアウト(グリッドエリア) */
.layout {
display: grid;
grid-template-areas:
"header header header"
"sidebar main main"
"footer footer footer";
grid-template-columns: 250px 1fr 1fr;
grid-template-rows: auto 1fr auto;
gap: 1rem;
min-height: 100vh;
}
.header {
grid-area: header;
background-color: #333;
color: white;
padding: 1rem;
}
.sidebar {
grid-area: sidebar;
background-color: #f5f5f5;
padding: 1rem;
}
.main {
grid-area: main;
padding: 1rem;
}
.footer {
grid-area: footer;
background-color: #333;
color: white;
padding: 1rem;
}
/* モバイル対応 */
@media (max-width: 768px) {
.layout {
grid-template-areas:
"header"
"main"
"sidebar"
"footer";
grid-template-columns: 1fr;
}
}
/* ギャラリーレイアウト */
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 1rem;
}
.gallery-item {
aspect-ratio: 1 / 1;
object-fit: cover;
}
/* カードレイアウト */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
}
.card {
display: flex;
flex-direction: column;
background: white;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.card-header {
padding: 1.5rem;
background-color: #f8f9fa;
}
.card-body {
padding: 1.5rem;
flex-grow: 1;
}
.card-footer {
padding: 1rem 1.5rem;
background-color: #f8f9fa;
border-top: 1px solid #e9ecef;
}2. Flexboxの活用
Flexboxは、1次元のレイアウト(行または列)を効率的に配置するためのCSSレイアウトモジュールです。要素を柔軟に配置でき、画面サイズに応じて自動的に調整されます。ナビゲーションバー、カードレイアウト、中央揃えなど、様々な場面で活用できます。
基本的なFlexbox
Flexboxの基本的な使い方:
Flexコンテナの設定:
.container {
display: flex;
flex-direction: row; /* row, column, row-reverse, column-reverse */
justify-content: center; /* 主軸方向の配置 */
align-items: center; /* 交差軸方向の配置 */
gap: 1rem;
}主なプロパティ:
-
display: flex: Flexboxを有効化-
flex-direction: 主軸の方向-
justify-content: 主軸方向の配置(flex-start, center, flex-end, space-between, space-around, space-evenly)-
align-items: 交差軸方向の配置(flex-start, center, flex-end, stretch, baseline)-
flex-wrap: 折り返し(nowrap, wrap, wrap-reverse)Flexアイテムのプロパティ:
-
flex: 伸縮の比率(flex-grow flex-shrink flex-basisのショートハンド)-
flex-grow: 伸びる比率(デフォルト: 0)-
flex-shrink: 縮む比率(デフォルト: 1)-
flex-basis: 基準となるサイズ(デフォルト: auto)実践的なFlexboxパターン
Flexboxを使用した実践的なパターン:
中央揃え:
.center {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}ナビゲーションバー:
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
}カードレイアウト:
.card-container {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.card {
flex: 1 1 300px; /* 最小幅300px、伸縮可能 */
}フッターを下部に固定:
body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.main {
flex: 1;
}Flexboxの高度な機能
Flexboxの高度な機能:
align-self:
個別のアイテムの配置を制御
.item {
align-self: flex-end;
}order:
アイテムの表示順序を変更(視覚的な順序のみ)
.item-1 { order: 2; }
.item-2 { order: 1; }flex-basisの活用:
.item {
flex: 0 0 200px; /* 固定幅200px */
}gapプロパティ:
アイテム間の間隔を簡単に設定(
row-gapとcolumn-gapのショートハンド)Flexboxの実装例
基本的なFlexboxから実践的なパターンまでの実装例です。
/* 基本的なFlexbox */
.flex-container {
display: flex;
gap: 1rem;
padding: 1rem;
}
.flex-item {
flex: 1;
padding: 1rem;
background-color: #f0f0f0;
}
/* 中央揃え */
.center {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
/* ナビゲーションバー */
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 2rem;
background-color: #333;
color: white;
}
.nav-links {
display: flex;
gap: 2rem;
list-style: none;
}
/* カードレイアウト */
.card-container {
display: flex;
flex-wrap: wrap;
gap: 2rem;
padding: 2rem;
}
.card {
flex: 1 1 300px;
max-width: 400px;
display: flex;
flex-direction: column;
background: white;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.card-header {
padding: 1.5rem;
border-bottom: 1px solid #e9ecef;
}
.card-body {
padding: 1.5rem;
flex-grow: 1;
}
.card-footer {
padding: 1rem 1.5rem;
border-top: 1px solid #e9ecef;
margin-top: auto;
}
/* フッターを下部に固定 */
body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.main-content {
flex: 1;
}
/* ボタングループ */
.button-group {
display: flex;
gap: 1rem;
flex-wrap: wrap;
}
.button {
flex: 1 1 auto;
min-width: 120px;
padding: 0.75rem 1.5rem;
}
/* モバイル対応 */
@media (max-width: 768px) {
.navbar {
flex-direction: column;
gap: 1rem;
}
.nav-links {
flex-direction: column;
width: 100%;
}
.card {
flex: 1 1 100%;
}
}3. CSS変数(カスタムプロパティ)
CSS変数(カスタムプロパティ)は、値を再利用し、テーマの切り替えや動的な値の計算を可能にする強力な機能です。--で始まる名前で定義し、var()関数で参照します。JavaScriptからも動的に変更できるため、テーマの切り替えなどに最適です。
基本的な使い方
CSS変数の基本的な使い方:
変数の定義:
:root {
--primary-color: #0066cc;
--secondary-color: #666666;
--spacing: 1rem;
--font-size-base: 16px;
}変数の使用:
.button {
background-color: var(--primary-color);
padding: var(--spacing);
font-size: var(--font-size-base);
}フォールバック値:
.color {
color: var(--text-color, #333333);
}変数が定義されていない場合、
#333333が使用されます。スコープ:
変数は定義された要素とその子要素で使用可能です。
:rootで定義すると、すべての要素で使用できます。テーマの切り替え
CSS変数を使用してテーマを切り替える方法:
テーマの定義:
:root {
--bg-color: #ffffff;
--text-color: #333333;
}
[data-theme="dark"] {
--bg-color: #1a1a1a;
--text-color: #ffffff;
}JavaScriptでの切り替え:
document.documentElement.setAttribute('data-theme', 'dark');複数のテーマ:
[data-theme="light"] { /* ライトテーマ */ }
[data-theme="dark"] { /* ダークテーマ */ }
[data-theme="high-contrast"] { /* ハイコントラストテーマ */ }動的な値の計算
CSS変数を使用して動的な値を計算する方法:
calc()との組み合わせ:
:root {
--base-size: 16px;
--spacing: 1rem;
}
.element {
font-size: calc(var(--base-size) * 1.5);
margin: calc(var(--spacing) * 2);
}JavaScriptからの変更:
document.documentElement.style.setProperty('--spacing', '2rem');条件付き値:
.element {
--size: var(--small-size, 100px);
}
@media (min-width: 768px) {
.element {
--size: var(--large-size, 200px);
}
}CSS変数の実装例
CSS変数の基本的な使い方からテーマ切り替えまでの実装例です。
/* CSS変数の定義 */
:root {
/* カラー */
--primary-color: #0066cc;
--secondary-color: #666666;
--success-color: #28a745;
--error-color: #dc3545;
--warning-color: #ffc107;
/* スペーシング */
--spacing-xs: 0.25rem;
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 1.5rem;
--spacing-xl: 2rem;
/* タイポグラフィ */
--font-size-base: 16px;
--font-size-sm: 0.875rem;
--font-size-lg: 1.25rem;
--font-size-xl: 1.5rem;
/* その他 */
--border-radius: 4px;
--box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
/* ダークテーマ */
[data-theme="dark"] {
--primary-color: #4da6ff;
--bg-color: #1a1a1a;
--text-color: #ffffff;
--border-color: #333333;
}
/* ライトテーマ */
[data-theme="light"] {
--bg-color: #ffffff;
--text-color: #333333;
--border-color: #e0e0e0;
}
/* 変数の使用 */
body {
background-color: var(--bg-color, #ffffff);
color: var(--text-color, #333333);
font-size: var(--font-size-base);
}
.button {
background-color: var(--primary-color);
color: white;
padding: var(--spacing-sm) var(--spacing-md);
border-radius: var(--border-radius);
box-shadow: var(--box-shadow);
border: none;
cursor: pointer;
transition: background-color 0.3s ease;
}
.button:hover {
background-color: color-mix(in srgb, var(--primary-color) 80%, black);
}
.card {
background-color: var(--bg-color);
border: 1px solid var(--border-color);
border-radius: var(--border-radius);
padding: var(--spacing-lg);
box-shadow: var(--box-shadow);
}
/* calc()との組み合わせ */
.container {
--container-width: 1200px;
--container-padding: var(--spacing-md);
max-width: var(--container-width);
padding: var(--container-padding);
margin: 0 auto;
}
.content {
width: calc(100% - var(--container-padding) * 2);
}
/* JavaScriptでのテーマ切り替え */
/*
const themeToggle = document.getElementById('theme-toggle');
const currentTheme = localStorage.getItem('theme') || 'light';
document.documentElement.setAttribute('data-theme', currentTheme);
themeToggle.addEventListener('click', () => {
const newTheme = currentTheme === 'light' ? 'dark' : 'light';
document.documentElement.setAttribute('data-theme', newTheme);
localStorage.setItem('theme', newTheme);
});
// 動的な値の変更
function updateSpacing(value) {
document.documentElement.style.setProperty('--spacing-md', value);
}
*/4. コンテナクエリ
コンテナクエリは、親要素のサイズに応じてスタイルを適用できる機能です。メディアクエリがビューポートのサイズに基づくのに対し、コンテナクエリは親要素のサイズに基づきます。これにより、コンポーネントベースのレスポンシブデザインが可能になります。
基本的な使い方
コンテナクエリの基本的な使い方:
コンテナの定義:
.card-container {
container-type: inline-size;
/* または */
container: card-container / inline-size;
}コンテナクエリの使用:
@container (min-width: 400px) {
.card {
display: flex;
flex-direction: row;
}
}コンテナ名の指定:
.sidebar {
container-name: sidebar;
container-type: inline-size;
}
@container sidebar (min-width: 300px) {
.widget {
/* スタイル */
}
}container-typeの値:
-
inline-size: インライン方向のサイズ(幅)-
block-size: ブロック方向のサイズ(高さ)-
size: 両方向のサイズコンテナクエリの単位
コンテナクエリの単位(cqw、cqh、cqi、cqb、cqmin、cqmax)を使用できます。
単位の説明:
- cqw: コンテナの幅の1%
- cqh: コンテナの高さの1%
- cqi: インライン方向のサイズの1%
- cqb: ブロック方向のサイズの1%
- cqmin: cqiとcqbの小さい方
- cqmax: cqiとcqbの大きい方
使用例:
.card {
font-size: clamp(1rem, 2cqw, 1.5rem);
padding: 2cqw;
}注意点:
- コンテナクエリは比較的新しい機能で、ブラウザサポートが限定的
- フォールバックとしてメディアクエリも併用することを推奨
コンテナクエリの実装例
コンテナクエリを使用した実装例です。
/* コンテナの定義 */
.card-container {
container-type: inline-size;
container-name: card-container;
}
/* コンテナクエリの使用 */
.card {
display: flex;
flex-direction: column;
padding: 1rem;
background: white;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
/* コンテナが400px以上の場合は横並び */
@container card-container (min-width: 400px) {
.card {
flex-direction: row;
gap: 1.5rem;
}
.card-image {
flex: 0 0 200px;
}
.card-content {
flex: 1;
}
}
/* コンテナが600px以上の場合はさらに調整 */
@container card-container (min-width: 600px) {
.card {
padding: 2rem;
}
.card-title {
font-size: 1.5rem;
}
}
/* コンテナクエリの単位を使用 */
.responsive-text {
font-size: clamp(1rem, 3cqw, 1.5rem);
padding: 2cqw;
}
/* サイドバーのコンテナクエリ */
.sidebar {
container-type: inline-size;
container-name: sidebar;
}
.widget {
padding: 1rem;
}
@container sidebar (min-width: 300px) {
.widget {
padding: 1.5rem;
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
}
}
/* フォールバック(メディアクエリ) */
@media (min-width: 768px) {
.card {
flex-direction: row;
}
}
/* コンテナクエリとメディアクエリの組み合わせ */
@container (min-width: 400px) and (max-width: 800px) {
.card {
/* スタイル */
}
}
@media (min-width: 1024px) {
@container (min-width: 500px) {
.card {
/* スタイル */
}
}
}5. モダンなセレクタ
モダンなCSSセレクタ(:is()、:where()、:has()、:focus-visibleなど)は、より柔軟で強力なスタイリングを可能にします。これらのセレクタを使用することで、コードを簡潔にし、保守性を向上させることができます。
:is()と:where()
:is()と:where()は、複数のセレクタをグループ化する疑似クラスです。
:is()の使用:
/* 従来の書き方 */
h1, h2, h3, h4, h5, h6 {
color: #333;
}
/* :is()を使用 */
:is(h1, h2, h3, h4, h5, h6) {
color: #333;
}:where()の使用:
:where()は:is()と同じですが、詳細度が0です。:where(h1, h2, h3) {
color: #333;
}実用例:
/* ネストされた要素のスタイリング */
article :is(h1, h2, h3) {
margin-top: 2rem;
}
/* フォーム要素のスタイリング */
:where(input, textarea, select):focus {
outline: 2px solid blue;
}:has()セレクタ
:has()は、「親セレクタ」として機能し、特定の子要素を持つ親要素を選択できます。
基本的な使い方:
/* 画像を含むカード */
.card:has(img) {
display: flex;
flex-direction: column;
}
/* エラーを含むフォーム */
.form:has(.error) {
border-color: red;
}
/* リンクを含む段落 */
p:has(a) {
font-weight: bold;
}実用例:
/* 子要素の状態に基づくスタイリング */
.nav:has(.active) {
background-color: #f0f0f0;
}
/* 条件付きレイアウト */
.container:has(.sidebar) {
display: grid;
grid-template-columns: 250px 1fr;
}:focus-visible
:focus-visibleは、キーボード操作でフォーカスされた場合のみスタイルを適用します。
使い方:
/* すべてのフォーカス */
button:focus {
outline: 2px solid blue;
}
/* キーボード操作でのみ */
button:focus-visible {
outline: 2px solid blue;
outline-offset: 2px;
}
/* マウスクリックでは非表示 */
button:focus:not(:focus-visible) {
outline: none;
}メリット:
- キーボードユーザーにはフォーカスインジケーターを表示
- マウスユーザーには不要なアウトラインを非表示
- アクセシビリティとUXの両立
モダンなセレクタの実装例
モダンなセレクタを使用した実装例です。
/* :is()の使用例 */
/* 見出しのスタイリング */
:is(h1, h2, h3, h4, h5, h6) {
color: #333;
font-weight: bold;
margin-top: 2rem;
margin-bottom: 1rem;
}
/* ネストされた要素 */
article :is(h1, h2, h3) {
border-bottom: 2px solid #0066cc;
padding-bottom: 0.5rem;
}
/* :where()の使用例(詳細度0) */
:where(header, footer, nav) a {
color: #0066cc;
text-decoration: none;
}
/* 上書き可能 */
header a {
color: white; /* これは適用される */
}
/* :has()の使用例 */
/* 画像を含むカード */
.card:has(img) {
display: flex;
flex-direction: column;
}
.card:has(img) .card-image {
order: -1;
margin-bottom: 1rem;
}
/* エラーを含むフォーム */
.form-group:has(.error) {
border-left: 4px solid #dc3545;
padding-left: 1rem;
}
.form-group:has(.error) label {
color: #dc3545;
}
/* アクティブな項目を含むナビゲーション */
.nav:has(.active) {
background-color: #f8f9fa;
}
/* サイドバーを含むレイアウト */
.layout:has(.sidebar) {
display: grid;
grid-template-columns: 250px 1fr;
gap: 2rem;
}
/* :focus-visibleの使用例 */
.button {
padding: 0.75rem 1.5rem;
background-color: #0066cc;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
/* キーボード操作でのみフォーカスインジケーターを表示 */
.button:focus-visible {
outline: 3px solid #0066cc;
outline-offset: 2px;
}
/* マウスクリックでは非表示 */
.button:focus:not(:focus-visible) {
outline: none;
}
/* リンクのスタイリング */
a:focus-visible {
outline: 2px solid #0066cc;
outline-offset: 2px;
border-radius: 2px;
}
/* フォーム要素 */
input:focus-visible,
textarea:focus-visible,
select:focus-visible {
outline: 2px solid #0066cc;
outline-offset: 2px;
border-color: #0066cc;
}6. アニメーションとトランジション
CSSアニメーションとトランジションは、ユーザー体験を向上させる重要な要素です。適切に使用することで、スムーズで自然な動きを実現できます。prefers-reduced-motionを尊重し、アクセシビリティも考慮することが重要です。
CSSアニメーション
CSSアニメーションの基本的な使い方:
アニメーションの定義:
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.element {
animation: fadeIn 0.5s ease-in-out;
}アニメーションプロパティ:
-
animation-name: アニメーション名-
animation-duration: 継続時間-
animation-timing-function: タイミング関数(ease, linear, ease-in-outなど)-
animation-delay: 遅延時間-
animation-iteration-count: 繰り返し回数(infiniteで無限)-
animation-direction: 方向(normal, reverse, alternateなど)-
animation-fill-mode: 開始前・終了後の状態(forwards, backwards, both)トランジション
トランジションは、プロパティの変化をスムーズにアニメーション化します。
基本的な使い方:
.button {
background-color: #0066cc;
transition: background-color 0.3s ease;
}
.button:hover {
background-color: #0052a3;
}複数のプロパティ:
.card {
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-4px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}トランジションプロパティ:
-
transition-property: トランジションを適用するプロパティ(allで全て)-
transition-duration: 継続時間-
transition-timing-function: タイミング関数-
transition-delay: 遅延時間スクロール連動アニメーション
スクロール連動アニメーションは、scroll-timelineやanimation-timelineを使用して実現できます(実験的機能)。
実装方法:
@keyframes scroll-animation {
from {
opacity: 0;
transform: translateY(50px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.element {
animation: scroll-animation linear;
animation-timeline: scroll();
}注意点:
- ブラウザサポートが限定的
- JavaScriptとの組み合わせも検討
-
Intersection Observer APIを使用した実装も一般的アニメーションとトランジションの実装例
CSSアニメーションとトランジションの実装例です。
/* フェードインアニメーション */
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.fade-in {
animation: fadeIn 0.5s ease-in-out;
}
/* スライドインアニメーション */
@keyframes slideInFromLeft {
from {
transform: translateX(-100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
.slide-in {
animation: slideInFromLeft 0.5s ease-out;
}
/* ボタンのトランジション */
.button {
background-color: #0066cc;
color: white;
padding: 0.75rem 1.5rem;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s ease, transform 0.2s ease, box-shadow 0.3s ease;
}
.button:hover {
background-color: #0052a3;
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
.button:active {
transform: translateY(0);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
/* カードのホバーエフェクト */
.card {
background: white;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-4px) scale(1.02);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
}
/* ローディングアニメーション */
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.loader {
border: 4px solid #f3f3f3;
border-top: 4px solid #0066cc;
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
}
/* パルスアニメーション */
@keyframes pulse {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0.5;
}
}
.pulse {
animation: pulse 2s ease-in-out infinite;
}
/* モーションを減らす設定を尊重 */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* 遅延アニメーション */
.stagger-item {
opacity: 0;
animation: fadeIn 0.5s ease-in-out forwards;
}
.stagger-item:nth-child(1) { animation-delay: 0.1s; }
.stagger-item:nth-child(2) { animation-delay: 0.2s; }
.stagger-item:nth-child(3) { animation-delay: 0.3s; }
.stagger-item:nth-child(4) { animation-delay: 0.4s; }7. レスポンシブデザインのテクニック
モダンなCSS関数(clamp()、min()、max()、aspect-ratioなど)を使用して、より柔軟なレスポンシブデザインを実現できます。これらの関数により、メディアクエリを減らし、より流動的なレイアウトを作成できます。
クランプ関数
clamp()関数は、値を最小値と最大値の間でクランプ(制限)します。
基本的な使い方:
font-size: clamp(1rem, 4vw, 2rem);
/* 最小1rem、推奨4vw、最大2rem */実用例:
/* レスポンシブなフォントサイズ */
.title {
font-size: clamp(1.5rem, 5vw, 3rem);
}
/* レスポンシブなパディング */
.container {
padding: clamp(1rem, 5vw, 3rem);
}
/* レスポンシブな幅 */
.content {
width: clamp(300px, 90vw, 1200px);
}aspect-ratio
aspect-ratioプロパティは、要素のアスペクト比を設定します。
基本的な使い方:
.image {
aspect-ratio: 16 / 9;
width: 100%;
height: auto;
}実用例:
/* 正方形の画像 */
.thumbnail {
aspect-ratio: 1 / 1;
object-fit: cover;
}
/* カードのアスペクト比 */
.card {
aspect-ratio: 4 / 3;
}
/* 動画コンテナ */
.video-container {
aspect-ratio: 16 / 9;
}min()、max()、clamp()
min()、max()、clamp()関数の使い分け:
min()の使用:
複数の値の最小値を選択
width: min(100%, 1200px);
/* 100%と1200pxの小さい方 */max()の使用:
複数の値の最大値を選択
padding: max(1rem, 5vw);
/* 1remと5vwの大きい方 */clamp()の使用:
値を最小値と最大値の間でクランプ
font-size: clamp(1rem, 4vw, 2rem);
/* 1rem以上2rem以下、推奨4vw */実用例:
/* コンテナの最大幅 */
.container {
width: min(100% - 2rem, 1200px);
margin: 0 auto;
}
/* 最小パディング */
.section {
padding: max(2rem, 5vw);
}レスポンシブデザインのテクニック実装例
clamp()、aspect-ratio、min()、max()を使用した実装例です。
/* clamp()の使用例 */
/* レスポンシブなフォントサイズ */
.title {
font-size: clamp(1.5rem, 5vw, 3rem);
line-height: 1.2;
}
.subtitle {
font-size: clamp(1rem, 3vw, 1.5rem);
}
/* レスポンシブなパディング */
.container {
padding: clamp(1rem, 5vw, 3rem);
}
.section {
padding-top: clamp(2rem, 8vw, 6rem);
padding-bottom: clamp(2rem, 8vw, 6rem);
}
/* レスポンシブな幅 */
.content {
width: clamp(300px, 90vw, 1200px);
margin: 0 auto;
}
/* aspect-ratioの使用例 */
/* 画像のアスペクト比 */
.image {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
}
.thumbnail {
aspect-ratio: 1 / 1;
object-fit: cover;
}
/* カードのアスペクト比 */
.card {
aspect-ratio: 4 / 3;
background: white;
border-radius: 8px;
overflow: hidden;
}
/* 動画コンテナ */
.video-container {
position: relative;
width: 100%;
aspect-ratio: 16 / 9;
background: #000;
}
.video-container iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
/* min()とmax()の使用例 */
/* コンテナの最大幅 */
.container {
width: min(100% - 2rem, 1200px);
margin: 0 auto;
}
/* 最小パディング */
.section {
padding: max(2rem, 5vw);
}
/* レスポンシブなギャップ */
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: max(1rem, 3vw);
}
/* 複数の値の組み合わせ */
.responsive-text {
font-size: clamp(
max(1rem, 2vw),
4vw,
min(2rem, 5vw)
);
}
/* 実践的な例:カードレイアウト */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(clamp(250px, 30vw, 400px), 1fr));
gap: clamp(1rem, 3vw, 2rem);
padding: clamp(1rem, 5vw, 3rem);
}
.card {
aspect-ratio: 4 / 3;
background: white;
border-radius: clamp(4px, 1vw, 8px);
padding: clamp(1rem, 3vw, 2rem);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.card-title {
font-size: clamp(1.25rem, 3vw, 1.5rem);
margin-bottom: clamp(0.5rem, 2vw, 1rem);
}8. レイアウトのベストプラクティス
GridとFlexboxの適切な使い分けと、モダンなリセットCSSの使用により、効率的で保守しやすいレイアウトを実現できます。各機能の特徴を理解し、適切な場面で適切な機能を選択することが重要です。
GridとFlexboxの使い分け
GridとFlexboxの使い分けのガイドライン:
Gridを使用する場合:
- 2次元レイアウト(行と列の両方を制御)
- 複雑なレイアウト(ヘッダー、サイドバー、メイン、フッターなど)
- アイテムの位置を正確に制御したい場合
- グリッドベースのデザイン
Flexboxを使用する場合:
- 1次元レイアウト(行または列のいずれか)
- ナビゲーションバー、ボタングループ
- アイテムの均等な配置
- 中央揃え
組み合わせて使用:
GridとFlexboxは競合するものではなく、組み合わせて使用できます。
.layout {
display: grid;
grid-template-columns: 250px 1fr;
}
.navbar {
display: flex;
justify-content: space-between;
}モダンなリセットCSS
モダンなリセットCSSの例:
基本的なリセット:
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
-webkit-text-size-adjust: 100%;
}
body {
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
img, picture, video, canvas, svg {
display: block;
max-width: 100%;
}
input, button, textarea, select {
font: inherit;
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word;
}注意点:
-
box-sizing: border-boxを設定- 画像の
max-width: 100%を設定- フォントの継承を設定
レイアウトのベストプラクティス実装例
GridとFlexboxの使い分けと、モダンなリセットCSSの実装例です。
/* モダンなリセットCSS */
*, *::before, *::after {
box-sizing: border-box;
}
* {
margin: 0;
padding: 0;
}
html {
-webkit-text-size-adjust: 100%;
text-size-adjust: 100%;
}
body {
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
img, picture, video, canvas, svg {
display: block;
max-width: 100%;
height: auto;
}
input, button, textarea, select {
font: inherit;
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word;
}
#root, #__next {
isolation: isolate;
}
/* GridとFlexboxの組み合わせ例 */
/* ページレイアウト(Grid) */
.page-layout {
display: grid;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
grid-template-columns: 250px 1fr;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
}
.header {
grid-area: header;
/* ナビゲーションバー(Flexbox) */
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 2rem;
}
.sidebar {
grid-area: sidebar;
/* サイドバーメニュー(Flexbox) */
display: flex;
flex-direction: column;
gap: 1rem;
padding: 1rem;
}
.main {
grid-area: main;
padding: 2rem;
}
.footer {
grid-area: footer;
/* フッターリンク(Flexbox) */
display: flex;
justify-content: center;
gap: 2rem;
padding: 1rem;
}
/* カードグリッド(Grid) */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
}
/* カード内のレイアウト(Flexbox) */
.card {
display: flex;
flex-direction: column;
background: white;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.card-header {
padding: 1.5rem;
}
.card-body {
padding: 1.5rem;
flex-grow: 1;
}
.card-footer {
padding: 1rem 1.5rem;
margin-top: auto;
display: flex;
justify-content: space-between;
align-items: center;
}9. パフォーマンス最適化
CSSのパフォーマンス最適化には、will-change、content-visibility、containプロパティなどの機能を適切に使用することが重要です。これらの機能により、レンダリングパフォーマンスを向上させ、ユーザー体験を改善できます。
will-change
will-changeプロパティは、要素が変更されることをブラウザに事前に通知します。
使い方:
.animated-element {
will-change: transform;
transition: transform 0.3s ease;
}
.animated-element:hover {
transform: translateY(-10px);
}注意点:
- 必要な要素にのみ使用(過度な使用は逆効果)
- アニメーション終了後に削除することを推奨
- JavaScriptで動的に設定・削除
推奨される使用例:
// アニメーション開始前に設定
element.style.willChange = 'transform';
// アニメーション終了後に削除
element.addEventListener('transitionend', () => {
element.style.willChange = 'auto';
});content-visibility
content-visibilityプロパティは、ビューポート外のコンテンツのレンダリングをスキップします。
使い方:
.long-content {
content-visibility: auto;
}
.section {
content-visibility: auto;
contain-intrinsic-size: 0 500px;
}値の説明:
-
visible: デフォルト(通常のレンダリング)-
hidden: コンテンツをスキップ(display: noneに近い)-
auto: ビューポート外のコンテンツをスキップcontain-intrinsic-size:
スキップされたコンテンツの推定サイズを指定
.section {
content-visibility: auto;
contain-intrinsic-size: 0 500px; /* 幅0、高さ500px */
}containプロパティ
containプロパティは、要素のレンダリングを分離し、パフォーマンスを向上させます。
使い方:
.widget {
contain: layout style paint;
}
.isolated-component {
contain: strict; /* layout style paint size のショートハンド */
}値の説明:
-
layout: レイアウトの分離-
style: スタイルの分離-
paint: ペイントの分離-
size: サイズの分離-
strict: すべての分離(layout style paint)-
content: レイアウトとペイントの分離使用例:
.card {
contain: layout style paint;
}
.modal {
contain: strict;
}パフォーマンス最適化の実装例
will-change、content-visibility、containプロパティを使用した実装例です。
/* will-changeの使用例 */
/* アニメーション要素 */
.animated-card {
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.animated-card:hover {
will-change: transform;
transform: translateY(-10px);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
}
/* JavaScriptでの動的な設定 */
/*
const card = document.querySelector('.animated-card');
card.addEventListener('mouseenter', () => {
card.style.willChange = 'transform';
});
card.addEventListener('transitionend', () => {
card.style.willChange = 'auto';
});
*/
/* content-visibilityの使用例 */
/* 長いリスト */
.long-list {
content-visibility: auto;
}
.list-item {
contain-intrinsic-size: 0 50px;
content-visibility: auto;
}
/* セクション */
.section {
content-visibility: auto;
contain-intrinsic-size: 0 500px;
padding: 2rem;
}
/* モーダル(非表示時) */
.modal.hidden {
content-visibility: hidden;
}
/* containプロパティの使用例 */
/* カードコンポーネント */
.card {
contain: layout style paint;
background: white;
border-radius: 8px;
padding: 1.5rem;
}
/* ウィジェット */
.widget {
contain: layout style paint;
isolation: isolate;
}
/* モーダル */
.modal {
contain: strict;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
/* リストアイテム */
.list-item {
contain: layout style;
padding: 1rem;
border-bottom: 1px solid #e0e0e0;
}
/* 組み合わせた最適化 */
.optimized-component {
/* レンダリングの分離 */
contain: layout style paint;
/* ビューポート外のコンテンツをスキップ */
content-visibility: auto;
contain-intrinsic-size: 0 200px;
/* アニメーションの最適化 */
will-change: transform;
transition: transform 0.3s ease;
}
.optimized-component:hover {
transform: scale(1.05);
}10. 実践的な例:カードコンポーネント
これまで学んだモダンなCSSテクニックを組み合わせた、実践的なカードコンポーネントの実装例です。Grid、Flexbox、CSS変数、アニメーション、レスポンシブデザインなどを統合した完全な例を示します。
モダンなCSSを使用したカードコンポーネント
Grid、Flexbox、CSS変数、アニメーションなどを組み合わせたカードコンポーネントの完全な実装例です。
/* CSS変数の定義 */
:root {
--card-bg: #ffffff;
--card-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
--card-shadow-hover: 0 8px 16px rgba(0, 0, 0, 0.15);
--card-border-radius: clamp(4px, 1vw, 8px);
--card-padding: clamp(1rem, 3vw, 2rem);
--card-gap: clamp(1rem, 3vw, 2rem);
--primary-color: #0066cc;
--text-color: #333333;
--text-color-light: #666666;
}
[data-theme="dark"] {
--card-bg: #1a1a1a;
--text-color: #ffffff;
--text-color-light: #cccccc;
--card-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
--card-shadow-hover: 0 8px 16px rgba(0, 0, 0, 0.5);
}
/* カードグリッド(Grid) */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(clamp(300px, 30vw, 400px), 1fr));
gap: var(--card-gap);
padding: var(--card-padding);
container-type: inline-size;
}
/* カードコンポーネント(Flexbox) */
.card {
display: flex;
flex-direction: column;
background: var(--card-bg);
border-radius: var(--card-border-radius);
box-shadow: var(--card-shadow);
overflow: hidden;
transition: transform 0.3s ease, box-shadow 0.3s ease;
contain: layout style paint;
aspect-ratio: 4 / 3;
}
.card:hover {
transform: translateY(-4px) scale(1.02);
box-shadow: var(--card-shadow-hover);
will-change: transform;
}
.card:focus-visible {
outline: 3px solid var(--primary-color);
outline-offset: 2px;
}
/* カード画像 */
.card-image {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
order: -1;
}
/* カードヘッダー */
.card-header {
padding: var(--card-padding);
padding-bottom: 0;
}
.card-title {
font-size: clamp(1.25rem, 3vw, 1.5rem);
color: var(--text-color);
margin-bottom: clamp(0.5rem, 2vw, 1rem);
line-height: 1.3;
}
/* カード本文 */
.card-body {
padding: var(--card-padding);
flex-grow: 1;
color: var(--text-color-light);
font-size: clamp(0.875rem, 2vw, 1rem);
line-height: 1.6;
}
/* カードフッター(Flexbox) */
.card-footer {
padding: var(--card-padding);
padding-top: 0;
margin-top: auto;
display: flex;
justify-content: space-between;
align-items: center;
gap: 1rem;
}
.card-button {
padding: clamp(0.5rem, 2vw, 0.75rem) clamp(1rem, 3vw, 1.5rem);
background-color: var(--primary-color);
color: white;
border: none;
border-radius: clamp(4px, 1vw, 6px);
cursor: pointer;
font-size: clamp(0.875rem, 2vw, 1rem);
transition: background-color 0.3s ease, transform 0.2s ease;
}
.card-button:hover {
background-color: color-mix(in srgb, var(--primary-color) 80%, black);
transform: translateY(-2px);
}
.card-button:focus-visible {
outline: 2px solid var(--primary-color);
outline-offset: 2px;
}
/* コンテナクエリでの調整 */
@container (min-width: 400px) {
.card {
aspect-ratio: 3 / 2;
}
}
@container (min-width: 600px) {
.card {
flex-direction: row;
aspect-ratio: auto;
}
.card-image {
flex: 0 0 40%;
aspect-ratio: 1 / 1;
}
}
/* モーションを減らす設定を尊重 */
@media (prefers-reduced-motion: reduce) {
.card,
.card-button {
transition: none;
}
.card:hover {
transform: none;
}
}
/* アクセシビリティ */
.card:has(.card-button:focus) {
box-shadow: var(--card-shadow-hover);
}11. ベストプラクティス
モダンなCSSを効果的に活用するためのベストプラクティスをまとめます。適切な機能の選択、パフォーマンスの考慮、アクセシビリティの確保などが重要です。
機能の選択
Grid vs Flexbox:
- 2次元レイアウト → Grid
- 1次元レイアウト → Flexbox
- 組み合わせて使用も可能
CSS変数の活用:
- テーマ管理
- 値の再利用
- 動的な値の変更
モダンな関数の使用:
- clamp(): レスポンシブな値
- min()/max(): 条件付き値
- aspect-ratio: アスペクト比の維持
パフォーマンスとアクセシビリティ
パフォーマンス:
- will-changeを必要な要素にのみ使用
- content-visibilityで長いページを最適化
- containでレンダリングを分離
アクセシビリティ:
- :focus-visibleでキーボードフォーカスを適切に表示
- prefers-reduced-motionを尊重
- 十分なコントラスト比を確保
まとめ
モダンなCSSの機能を活用することで、より効率的で保守しやすいスタイルシートを書くことができます。CSS GridとFlexboxの適切な使い分け、CSS変数によるテーマ管理、コンテナクエリによるコンポーネントベースのレスポンシブデザインなど、様々なテクニックを組み合わせることで、モダンなWebサイトを構築できます。
重要なのは、各機能の特徴を理解し、適切な場面で適切な機能を選択することです。Gridは2次元レイアウトに、Flexboxは1次元レイアウトに適しています。CSS変数はテーマ管理や値の再利用に、コンテナクエリはコンポーネントベースのレスポンシブデザインに適しています。
実践的なプロジェクトでこれらのテクニックを活用し、様々なデバイスとブラウザでテストすることで、より良いWebサイトを構築できるようになります。