Menu

CSS calc() の使い方: 単位の混在、書き方のルール、例

calc() を使うと CSS の中で計算ができ、100% から固定の 200px のサイドバーを引くように、単位を混ぜられます。書き方のルール (空白が重要)、CSS 変数と組み合わせた calc()、calc() で解決できるよくあるレイアウト、無効な calc() が黙って無視される理由を解説します。

このページのコードはエディタで実行できます - 編集してすぐに結果を確認できます。

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 と同じ計算を書けます。

Coddy programming languages illustration

Coddyでコードを学ぼう

始める