CSS関数は、静的な値だけでは実現できない柔軟で動的なスタイル定義を可能にします。calc()による数学的計算、min()/max()による制約付きサイズ、clamp()による流動的なサイジングを組み合わせることで、メディアクエリに頼らないスマートなレスポンシブデザインを実装できます。

この記事では、CSS関数の基本構文から実践的な使用パターンまで、具体的なコード例を交えて解説します。

前提条件

項目 内容
対象読者 CSSの基本的なプロパティと単位を理解している方
必要な知識 ボックスモデル、レスポンシブデザインの基礎概念
ブラウザ対応 すべてのモダンブラウザで対応済み(IE非対応)

calc()関数の基本と活用法

calc()とは

calc()関数は、CSSプロパティの値として数学的な計算式を記述できる関数です。異なる単位同士の計算が可能で、レイアウトの動的な調整に威力を発揮します。

1
2
/* 基本構文 */
width: calc(100% - 40px);

calc()の演算子と構文ルール

calc()では4つの基本演算子を使用できます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
.element {
  /* 加算: + */
  width: calc(100% + 20px);
  
  /* 減算: - */
  height: calc(100vh - 80px);
  
  /* 乗算: * (少なくとも一方は数値) */
  padding: calc(1rem * 2);
  
  /* 除算: / (右辺は数値のみ) */
  margin: calc(100% / 3);
}

構文上の重要なルールとして、加算(+)と減算(-)の演算子の前後には必ず半角スペースが必要です。

1
2
3
4
5
/* 正しい書き方 */
width: calc(100% - 40px);

/* 誤った書き方(動作しない) */
width: calc(100%-40px);

乗算と除算ではスペースは必須ではありませんが、可読性のためにスペースを入れることを推奨します。

異なる単位間の計算

calc()の最大の特徴は、異なる単位を組み合わせた計算が可能な点です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
.container {
  /* パーセンテージとピクセルの組み合わせ */
  width: calc(100% - 2rem);
  
  /* ビューポート単位とピクセルの組み合わせ */
  height: calc(100vh - 60px);
  
  /* rem と em の組み合わせ */
  font-size: calc(1rem + 0.5em);
}

calc()の入れ子(ネスト)

calc()は入れ子にして複雑な計算を表現できます。

1
2
3
4
5
6
7
.sidebar {
  /* 入れ子の calc() */
  width: calc(calc(100% - 2rem) / 3);
  
  /* 括弧を使った簡略化(推奨) */
  width: calc((100% - 2rem) / 3);
}

入れ子のcalc()は通常の括弧に置き換えられるため、可読性を考慮して括弧を使う書き方が推奨されます。

calc()の実践的な使用例

固定サイドバーとフレキシブルメインエリア

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
.layout {
  display: flex;
}

.sidebar {
  width: 280px;
  flex-shrink: 0;
}

.main-content {
  /* サイドバーとギャップを除いた残りの幅 */
  width: calc(100% - 280px - 2rem);
}

ヘッダー・フッターを除いた高さ

1
2
3
4
.page-content {
  /* ヘッダー60px、フッター80pxを除いた高さ */
  min-height: calc(100vh - 60px - 80px);
}

均等なカラムレイアウト

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
.card-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

.card {
  /* 3カラム: ギャップを考慮した幅計算 */
  width: calc((100% - 2rem) / 3);
}

min()関数で最大値を制限する

min()とは

min()関数は、カンマで区切られた複数の値の中から最も小さい値を選択します。要素のサイズに上限を設けたい場合に有効です。

1
2
/* 基本構文 */
width: min(100%, 800px);

この例では、親要素の幅が800px以下なら100%、800pxを超えると800pxが適用されます。

min()の動作原理

1
2
3
4
.container {
  /* ビューポート幅の90%か、600pxの小さい方 */
  width: min(90vw, 600px);
}
graph LR
    A[ビューポート幅] --> B{90vw vs 600px}
    B -->|90vw < 600px| C[90vwを適用]
    B -->|90vw >= 600px| D[600pxを適用]

min()の実践的な使用例

最大幅を持つコンテナ

1
2
3
4
5
.container {
  /* max-width と同等の効果 */
  width: min(100%, 1200px);
  margin-inline: auto;
}

複数の制約を持つサイズ

1
2
3
4
.modal {
  /* 画面幅の90%、500px、親要素幅のうち最小のもの */
  width: min(90vw, 500px, 100%);
}

レスポンシブなパディング

1
2
3
4
.section {
  /* 画面幅に応じたパディング(上限4rem) */
  padding-inline: min(5vw, 4rem);
}

max()関数で最小値を保証する

max()とは

max()関数は、複数の値の中から最も大きい値を選択します。要素のサイズに下限を設けたい場合に有効です。

1
2
/* 基本構文 */
width: max(50%, 300px);

この例では、親要素幅の50%か300pxの大きい方が適用されます。

max()の動作原理

1
2
3
4
.sidebar {
  /* 親要素の25%か、200pxの大きい方 */
  width: max(25%, 200px);
}
graph LR
    A[親要素幅] --> B{25% vs 200px}
    B -->|25% > 200px| C[25%を適用]
    B -->|25% <= 200px| D[200pxを適用]

max()の実践的な使用例

最小幅を保証するサイドバー

1
2
3
4
.sidebar {
  /* 最低でも250pxは確保 */
  width: max(20%, 250px);
}

アクセシブルなフォントサイズ

1
2
3
4
body {
  /* 最低16pxを保証しつつ、大画面では拡大 */
  font-size: max(16px, 1vw);
}

タッチターゲットの最小サイズ保証

1
2
3
4
5
.button {
  /* タッチ操作のための最小サイズ(44px)を保証 */
  min-height: max(44px, 2.5rem);
  min-width: max(44px, 2.5rem);
}

clamp()関数で範囲内に値を制約する

clamp()とは

clamp()関数は、最小値・推奨値・最大値の3つの引数を受け取り、推奨値を最小値と最大値の範囲内に制約します。これはmin()max()を組み合わせた効果と同等です。

1
2
3
4
5
/* 基本構文 */
width: clamp(最小値, 推奨値, 最大値);

/* 例: 300px〜600pxの範囲で50%の幅 */
width: clamp(300px, 50%, 600px);

clamp()の動作原理

1
2
3
.container {
  width: clamp(300px, 50%, 800px);
}
graph TD
    A[推奨値 50% を評価] --> B{50% < 300px?}
    B -->|Yes| C[300pxを適用]
    B -->|No| D{50% > 800px?}
    D -->|Yes| E[800pxを適用]
    D -->|No| F[50%を適用]

clamp(300px, 50%, 800px)は、以下の式と等価です。

1
2
/* clamp() と等価な表現 */
width: max(300px, min(50%, 800px));

流動的タイポグラフィ(Fluid Typography)

clamp()の最も強力な活用法の一つが、流動的タイポグラフィです。メディアクエリなしで画面サイズに応じてスムーズにフォントサイズを変化させられます。

1
2
3
4
5
6
7
8
9
h1 {
  /* 24px〜48pxの範囲で、ビューポートに応じて変化 */
  font-size: clamp(1.5rem, 4vw + 1rem, 3rem);
}

p {
  /* 本文: 16px〜20pxの範囲 */
  font-size: clamp(1rem, 0.5vw + 0.9rem, 1.25rem);
}

流動的タイポグラフィの計算式

推奨値は通常、vw単位と固定値を組み合わせて設計します。

1
2
/* 計算式: vw係数 * 1vw + 基準値 */
font-size: clamp(1rem, 2vw + 0.5rem, 2rem);

320px〜1200pxの画面幅で16px〜32pxに変化させたい場合の計算例を示します。

1
2
3
4
5
6
7
/*
 * 変化量: 32px - 16px = 16px
 * ビューポート範囲: 1200px - 320px = 880px
 * vw係数: 16 / 880 * 100 = 約1.818vw
 * 320pxでの調整: 16px - (320 * 0.01818) = 約10.2px
 */
font-size: clamp(1rem, 1.818vw + 0.64rem, 2rem);

clamp()の実践的な使用例

レスポンシブなコンテナ幅

1
2
3
4
5
.container {
  /* 320px〜1200pxの範囲で90%の幅 */
  width: clamp(320px, 90%, 1200px);
  margin-inline: auto;
}

流動的な余白

1
2
3
4
.section {
  /* 画面サイズに応じて2rem〜6remの範囲で変化 */
  padding-block: clamp(2rem, 5vw + 1rem, 6rem);
}

カードの最適幅

1
2
3
4
.card {
  /* 280px〜400pxの範囲で、親要素に応じて変化 */
  width: clamp(280px, 100%, 400px);
}

CSS関数の組み合わせと応用テクニック

calc()とclamp()の組み合わせ

CSS関数は入れ子にして使用できます。

1
2
3
4
5
6
7
.element {
  /* clamp内でcalcを使用 */
  width: clamp(200px, calc(50% - 2rem), 600px);
  
  /* calc内でclampを使用 */
  padding: calc(clamp(1rem, 3vw, 3rem) / 2);
}

min()とmax()でclamp()を再現

clamp()がサポートされていない環境(現在はほぼ存在しませんが)では、min()max()で同様の効果を得られます。

1
2
/* clamp(1rem, 4vw, 3rem) と等価 */
font-size: max(1rem, min(4vw, 3rem));

カスタムプロパティとの連携

CSS関数はカスタムプロパティ(CSS変数)と組み合わせることで、より保守性の高いコードになります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
:root {
  --min-font-size: 1rem;
  --max-font-size: 2rem;
  --fluid-factor: 4vw;
  
  --container-padding: 1.5rem;
  --max-container-width: 1200px;
}

h1 {
  font-size: clamp(
    var(--min-font-size),
    var(--fluid-factor),
    var(--max-font-size)
  );
}

.container {
  width: min(
    calc(100% - var(--container-padding) * 2),
    var(--max-container-width)
  );
  margin-inline: auto;
}

レスポンシブグリッドでの活用

1
2
3
4
5
6
7
8
9
.card-grid {
  display: grid;
  /* 最小280px、最大1frで自動調整 */
  grid-template-columns: repeat(
    auto-fit,
    minmax(min(280px, 100%), 1fr)
  );
  gap: clamp(1rem, 3vw, 2rem);
}

このminmax(min(280px, 100%), 1fr)は、コンテナが280px未満の場合でもグリッドが壊れないようにする定番のテクニックです。

実装例: 流動的なページレイアウト

CSS関数を活用した、完全にレスポンシブなページレイアウトの実装例を示します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
:root {
  /* カラーとスペーシングの基準値 */
  --color-primary: #2563eb;
  --color-background: #f8fafc;
  --color-text: #1e293b;
  
  /* 流動的なスペーシング */
  --space-xs: clamp(0.5rem, 1vw, 0.75rem);
  --space-sm: clamp(0.75rem, 2vw, 1rem);
  --space-md: clamp(1rem, 3vw, 1.5rem);
  --space-lg: clamp(1.5rem, 4vw, 2.5rem);
  --space-xl: clamp(2rem, 6vw, 4rem);
  
  /* 流動的なフォントサイズ */
  --font-size-sm: clamp(0.875rem, 0.5vw + 0.75rem, 1rem);
  --font-size-base: clamp(1rem, 0.5vw + 0.875rem, 1.125rem);
  --font-size-lg: clamp(1.25rem, 1vw + 1rem, 1.5rem);
  --font-size-xl: clamp(1.5rem, 2vw + 1rem, 2.25rem);
  --font-size-2xl: clamp(2rem, 3vw + 1rem, 3rem);
}

body {
  font-size: var(--font-size-base);
  line-height: 1.7;
  color: var(--color-text);
  background-color: var(--color-background);
}

/* ヘッダー */
.header {
  position: sticky;
  top: 0;
  padding-block: var(--space-sm);
  padding-inline: var(--space-md);
}

/* メインコンテナ */
.container {
  width: min(calc(100% - var(--space-md) * 2), 1200px);
  margin-inline: auto;
}

/* セクション */
.section {
  padding-block: var(--space-xl);
}

/* 見出し */
.section-title {
  font-size: var(--font-size-2xl);
  margin-bottom: var(--space-lg);
}

/* カードグリッド */
.card-grid {
  display: grid;
  grid-template-columns: repeat(
    auto-fit,
    minmax(min(300px, 100%), 1fr)
  );
  gap: var(--space-md);
}

.card {
  padding: var(--space-md);
  background: white;
  border-radius: clamp(0.5rem, 1vw, 1rem);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

.card-title {
  font-size: var(--font-size-lg);
  margin-bottom: var(--space-sm);
}

/* サイドバー付きレイアウト */
.layout-with-sidebar {
  display: grid;
  grid-template-columns: 1fr min(300px, 30%);
  gap: var(--space-lg);
}

@media (max-width: 768px) {
  .layout-with-sidebar {
    grid-template-columns: 1fr;
  }
}

/* フッター */
.footer {
  margin-top: auto;
  padding-block: var(--space-lg);
  padding-inline: var(--space-md);
}

CSS関数のブラウザ対応状況

すべてのCSS関数はモダンブラウザで広くサポートされています(2026年1月現在)。

関数 Chrome Firefox Safari Edge
calc() 26+ 16+ 7+ 12+
min() 79+ 75+ 11.1+ 79+
max() 79+ 75+ 11.1+ 79+
clamp() 79+ 75+ 13.1+ 79+

Internet Explorerではcalc()のみサポートされており、min()max()clamp()は非対応です。IEのサポートが不要であれば、これらの関数は積極的に活用できます。

よくある間違いと注意点

演算子の前後にスペースがない

1
2
3
4
5
/* 誤り: スペースがない */
width: calc(100%-20px);

/* 正しい: 前後にスペースを入れる */
width: calc(100% - 20px);

ゼロ除算

1
2
/* 誤り: ゼロで割ると無効になる */
width: calc(100% / 0);

単位の不整合

1
2
3
4
5
/* 誤り: 数値同士で割る場合、結果は無単位になる */
width: calc(100px / 50px); /* 結果は「2」(単位なし)、widthには不正 */

/* 正しい: 単位を持つ値を返す */
width: calc(100px / 2); /* 結果は50px */

clamp()の引数順序

1
2
3
4
5
/* 誤り: 最小値が最大値より大きい(論理的に不正) */
font-size: clamp(3rem, 4vw, 1rem);

/* 正しい: 最小値 < 最大値 */
font-size: clamp(1rem, 4vw, 3rem);

まとめ

CSS関数を使いこなすことで、メディアクエリを大幅に削減しながら、より柔軟で堅牢なスタイル定義が可能になります。

関数 主な用途
calc() 異なる単位間の計算、動的なサイズ調整
min() サイズの上限設定(max-widthの代替)
max() サイズの下限設定(min-widthの代替)
clamp() 範囲制約付きの流動的サイジング

これらの関数をカスタムプロパティと組み合わせることで、保守性が高く、あらゆる画面サイズに対応したモダンなCSSを書けるようになります。まずはclamp()を使った流動的タイポグラフィから始めて、徐々に活用範囲を広げていくことをおすすめします。

参考リンク