calc() の役割
calc() は CSS の値の中で計算をし、レイアウトのときに初めてサイズが決まる単位を混ぜられます。定番は「幅いっぱいから固定のサイドバーを引く」ケースです:
100% はページが配置されて初めてわかり、180px は固定なので、1 つの単位ではこれを表せません。calc() がそれを計算します。幅 800px のプレビューでは行が 784px で、メインの列は 604px になり、レイアウトの下の行に実際の数値が表示されます。今ならこのレイアウトは flexbox や grid で計算なしにできますが、同じ引き算は今もあちこちで出てきます。高さからヘッダーを引く、幅からすき間を引く、といった場面です。
書き方のルール
width: calc(100% - 2rem); /* + and - need spaces on both sides */
width: calc(100% / 3); /* divide by a plain number */
margin: calc(var(--space) * 2); /* multiply by a plain number */
height: calc(100vh - (64px + 1rem)); /* parentheses group */
| ルール | 有効 | 無効 |
|---|---|---|
+ と - の前後に空白 | calc(100% - 20px) | calc(100%-20px) |
*: 少なくとも片側がただの数値 | calc(2 * 1rem) | calc(2px * 3px) |
/: 長さをただの数値で割る | calc(100% / 3) | width: calc(300px / 3px) (長さにならない) |
| 単位に互換性が必要 | calc(1rem + 10px) | calc(1rem + 2s) |
空白のルールがあるのは、100% -20px が 2 つの別々の値 (2 つ目は負の数) として読まれてしまうからです。calc() が無効だと宣言全体が捨てられ、要素はそれより前のルールで決まっていた値を保ちます。
式を試す
ボックスの幅に好きな式を入力してください。ブラウザが式の有効か無効かと、計算された幅を表示します:
100%-200px (空白がないので無効)、100% / 3、50% + 4rem、2 * 120px、200px * 2px (無効)、(100% - 40px) / 2 を試してみてください。
CSS 変数と calc()
変数と calc() は相性が良く、基本の値を 1 回だけ保存し、ほかの値をそこから導けます。単位のない変数は、1 単位を掛けると長さになります:
--space を 12px に、--cols を 4 に変えると、導かれた値がすべて追従します。変数の宣言と有効範囲は CSS 変数のページ で解説しています。
よくある使い方
| やりたいこと | calc() |
|---|---|
| 固定の要素の横の空きを埋める | width: calc(100% - 240px) |
| 固定ヘッダーの下のセクション | min-height: calc(100vh - 64px) |
| 幅の半分からすき間の半分を引く | width: calc(50% - 8px) |
| absolute で配置した 100px のボックスを中央に置く | left: calc(50% - 50px) |
| 画面に合わせて少しだけ大きくなるフォントサイズ | font-size: calc(1rem + 0.5vw) |
| 数値の変数を長さに変える | calc(var(--n) * 1px) |
| 変数の符号を反転する | calc(var(--space) * -1) |
値を限界の間に保ちたいなら clamp() を使いましょう。clamp() は calc() と書かなくても、引数の中で同じ計算を受け付けます。
calc() が使える場所
長さ、パーセント、数値、角度、時間が使える場所ならどこでも使えます。width、margin、padding、top、font-size、line-height、grid のトラックのサイズ、transition-delay、transform の中の角度などです。入れ子にもでき、入れ子の calc() は普通のかっこと同じ意味です。
角度はよい例です。下の目盛りはそれぞれ自分の --i (0 から 11) を持ち、1 つのルールが calc(var(--i) * 30deg) でそれを角度に変えます:
目盛り 3 は rotate(90deg) になり、Chrome はそれを行列 matrix(0, 1, -1, 0, 0, 0)、つまり 4 分の 1 回転として報告します。left: calc(50% - 2px) は、目盛り自身の幅 4px の半分を引いて、各目盛りを中央に置いています。
よくある間違い
-や+の前後に空白がない。calc(100%-20px)は無効で、無視されます。- 長さ同士を掛ける。
calc(10px * 2px)は CSS では意味を持ちません。*の片側はただの数値でなければなりません。 - 親に高さがないのに、パーセントの高さに calc() を使う。
heightのcalc(100% - 20px)には、height: 100%と同じく、高さが指定された親が必要です。 - flexbox や grid で済むところに calc() を使う。 段組みに
width: calc(33.333% - 10px)を使うと崩れやすくなります。display: grid; grid-template-columns: repeat(3, 1fr); gap: 15pxなら計算は要りません。 - エラーメッセージが出ると思う。 ブラウザは無効な calc() について警告しません。開発者ツールで要素を確認しましょう。無効な宣言には取り消し線が引かれています。
よくある質問
CSS の calc() は何をしますか?
+、-、*、/ を使った式から値を計算し、レイアウトのときにしかブラウザがわからない単位を混ぜられます。width: calc(100% - 200px) は、親の幅がいくつでも、親の幅いっぱいから 200px を引いた値です。
calc() が効かないのはなぜですか?
一番多い原因は空白の不足です。+ と - は前後に空白が必要なので、calc(100%-20px) は無効です。ほかには、長さ同士の掛け算 (10px * 2px) や長さでの割り算で、これらは長さになりません。無効な calc() は宣言全体を無効にするので、ブラウザはそれを無視します。
calc() の中で CSS 変数を使えますか?
使えます。calc(var(--gap) * 2) で変数を 2 倍にでき、calc(var(--columns) * 1px) で単位のない数値をピクセルに変えられます。先に変数の値が代入され、その後で計算されます。
calc() の * と / の前後に空白は必要ですか?
必要ありません。空白が必要なのは + と - だけです。空白がないと -20px が負の数として読まれるからです。* と / の前後の空白は任意ですが、どこにでも空白を書くのが一番覚えやすいルールです。
calc() と clamp() の違いは何ですか?
calc() は式から 1 つの値を計算します。clamp(MIN, VAL, MAX) は値を 2 つの限界の間に保ちます。2 つは組み合わせられます。clamp() の各引数には、clamp(1rem, 1rem + 2vw, 3rem) のように、最初から calc と同じ計算を書けます。