自分だけのブログを始めませんか?
WordPressブログなら、あなたのコーディング知識でデザインのカスタマイズが自由自在。
ブログデビューに最適な初心者向けサーバー環境を徹底比較しました。

WordPressブログなら、あなたのコーディング知識でデザインのカスタマイズが自由自在。
ブログデビューに最適な初心者向けサーバー環境を徹底比較しました。
CSSのcalc()関数は、異なる単位を混ぜて四則演算を行い、レスポンシブなレイアウトを制御する必須機能です。
本記事では、初心者がハマる「演算子前後のスペース」の罠から、CSS変数との高度な連携、最新の数学関数(min/max/clamp/round)まで実務で使える計算を解説します。
Webデザインをコーディングしていると、「画面幅の半分から、あと20pxだけ引きたい」「3等分した幅にしたいけれど、割り切れない数値になってしまう」といったレイアウトの悩みに直面します。
そんな時に便利なのがcalc()です。
calc()とは、CSSの中で直接「足し算・引き算・掛け算・割り算」の計算を行い、その結果をプロパティの値として適用できる関数です。
ここでは、calc()構文の基本から、プロパティにどのように適用するのか、初心者が100%ハマる「calc()が効かない」原因まで解説します。
calc()が効かない!演算子の前後の半角スペースcalc()が実務で多用される理由は「異なる単位を混ぜて計算できる」という点にあります。
例えば、100%から50pxを引く、50vwに2remを足すといったことが可能です。
100%や100vwや50%などを基準にして、そこから固定値(px)を引くことで、画面サイズが可変になっても崩れないレイアウトを作ることができます。
異なる単位を混ぜるには、『可変の単位(%やvw)』と『固定の単位(pxやrem)』を組み合わせて計算することです。
例えば、画面いっぱいの幅から、サイドバーの固定幅(300px)を引いた残りをメインエリアにする場合、width: calc(100% - 300px);と記述します。
これが現代のレスポンシブレイアウトのパターンです。
⭕️ ウィンドウ幅を変えても崩れない!100%から固定pxを引く!
❌ 罠(単位がない)
⭕️ 成功(異なる単位の計算)
<div class="calc-unit-wrapper">
<p class="calc-caption">⭕️ ウィンドウ幅を変えても崩れない!100%から固定pxを引く!</p>
<div class="calc-demo-area">
<div class="calc-trap-box">
<p class="demo-title is-error">❌ 罠(単位がない)</p>
<div class="trap-bar">
計算失敗(はみ出す)
</div>
</div>
<div class="calc-success-box">
<p class="demo-title is-success">⭕️ 成功(異なる単位の計算)</p>
<div class="success-container">
<div class="success-bar">
calc(100% - 50px)
</div>
<div class="fixed-block">
50px
</div>
</div>
</div>
</div>
<div class="calc-code-area">
<span class="hl-comment">/* ❌ 罠:50に単位がないため計算されず、指定が無効になる */</span><br>
<span class="hl-blue">.trap-bar</span> {<br>
<span class="hl-green">width:</span> <span class="hl-red">calc(100% - 50);</span> <span class="hl-comment">/* 🚨 ブラウザ「50って何?px?%?計算できない!」 */</span><br>
<span class="hl-green">background-color:</span> <span class="hl-red">#dc3545;</span><br>
}<br><br>
<span class="hl-comment">/* ⭕️ 異なる単位を組み合わせて、完璧な隙間(50px)を作る */</span><br>
<span class="hl-blue">.success-bar</span> {<br>
<span class="hl-green">width:</span> <span class="hl-red">calc(100% - 50px);</span> <span class="hl-comment">/* 💡 100%の幅から、正確に50pxだけ引く */</span><br>
<span class="hl-green">background-color:</span> <span class="hl-red">#198754;</span><br>
}<br>
<span class="hl-blue">.fixed-block</span> {<br>
<span class="hl-green">width:</span> <span class="hl-red">50px;</span> <span class="hl-comment">/* 💡 ここにピッタリはまる */</span><br>
}
</div>
</div>.calc-unit-wrapper {
background-color: #f8f9fa;
padding: 30px;
border-radius: 8px;
border: 1px solid #dee2e6;
}
.calc-caption {
font-size: 14px;
font-weight: bold;
margin-bottom: 20px;
color: #198754;
text-align: center;
}
.calc-demo-area {
display: flex;
flex-direction: column;
gap: 30px;
background-color: #e9ecef;
padding: 40px 20px;
border-radius: 8px;
border: 1px dashed #adb5bd;
margin-bottom: 40px;
}
.calc-trap-box,
.calc-success-box {
background-color: #ffffff;
padding: 20px;
border: 1px solid #ced4da;
border-radius: 4px;
width: 100%;
box-sizing: border-box;
}
.demo-title {
margin-top: 0;
margin-bottom: 15px;
font-size: 14px;
font-weight: bold;
}
.is-error { color: #dc3545; }
.is-success { color: #198754; }
/* === ❌ 罠:単位がない計算 === */
.trap-bar {
/* 🚨 計算が無効になり、親の幅を突き破る(または初期値になる) */
width: calc(100% - 50);
/* 見た目上は100%になってしまうことが多い */
width: 100%; /* ※デモの表示担保用 */
background-color: #dc3545;
color: #ffffff;
padding-top: 10px;
padding-bottom: 10px;
font-weight: bold;
text-align: center;
}
/* === ⭕️ 成功:単位を混ぜた計算 === */
.success-container {
display: flex;
width: 100%;
background-color: #f1f3f5;
border: 1px solid #ccc;
}
.success-bar {
/* 💡 100%から50pxを引く */
width: calc(100% - 50px);
background-color: #198754;
color: #ffffff;
padding-top: 10px;
padding-bottom: 10px;
font-weight: bold;
text-align: center;
}
.fixed-block {
width: 50px;
background-color: #0d6efd;
color: #ffffff;
padding-top: 10px;
padding-bottom: 10px;
font-weight: bold;
text-align: center;
font-size: 11px;
}
/* =コード解説エリア(エディタ風)= */
.calc-code-area {
background-color: #282c34;
color: #abb2bf;
padding: 20px;
border-radius: 6px;
font-family: monospace;
font-size: 13px;
line-height: 1.6;
border-left-style: solid;
border-left-width: 4px;
border-left-color: #0d6efd;
overflow-x: auto;
text-align: left;
}
.hl-blue { color: #61afef; font-weight: bold; }
.hl-red { color: #e06c75; font-weight: bold; }
.hl-green { color: #98c379; font-weight: bold; }
.hl-comment { color: #6c757d; font-style: italic; }calc()の中では、四則演算(+、-、*、/)を自由に行うことができます。
特に実務でよく使われるのが、3等分(100% / 3)などの割り算やフォントサイズを画面幅に合わせて比率で大きくする掛け算です。
また、要素を逆方向に動かすために、意図的にマイナスを作り出すテクニックも高度なアニメーションなどで活躍します。
複数の演算を組み合わせる場合は、数学と同じように()括弧を使って計算の優先順位をコントロールします。
四則演算は、足し算(+)と引き算(-)は『両方に単位』をつけ、掛け算(*)と割り算(/)は『片方は単位なしの数値』にする形がよいです。(例:calc(100% / 3))
このルールを徹底し、3カラムレイアウトなどで割り切れない33.3333%を手書きするのをやめ、calc(100% / 3)に任せてブラウザに極限まで正確な計算をさせます。
⭕️ ブラウザに計算を任せろ!掛け算・割り算の時は「片方を単位なし」にするのが鉄則だ!
❌ 罠(割り算に単位)
⭕️ 成功(正確な3等分)
<div class="calc-math-wrapper">
<p class="calc-caption">⭕️ ブラウザに計算を任せろ!掛け算・割り算の時は「片方を単位なし」にするのが鉄則だ!</p>
<div class="calc-demo-area">
<div class="calc-trap-box">
<p class="demo-title is-error">❌ 罠(割り算に単位)</p>
<div class="divide-trap">
100% / 3% はエラー
</div>
</div>
<div class="calc-success-box">
<p class="demo-title is-success">⭕️ 成功(正確な3等分)</p>
<div class="divide-container">
<div class="divide-box">1/3</div>
<div class="divide-box">1/3</div>
<div class="divide-box">1/3</div>
</div>
</div>
</div>
<div class="calc-code-area">
<span class="hl-comment">/* ❌ 罠:割り算なのに両方に単位(%)をつけてしまった */</span><br>
<span class="hl-blue">.divide-trap</span> {<br>
<span class="hl-green">width:</span> <span class="hl-red">calc(100% / 3%);</span> <span class="hl-comment">/* 🚨 エラーになり計算されない */</span><br>
}<br><br>
<span class="hl-comment">/* ⭕️ 割り算は「単位あり / 単位なし」の形にする! */</span><br>
<span class="hl-blue">.divide-box</span> {<br>
<span class="hl-green">width:</span> <span class="hl-red">calc(100% / 3);</span> <span class="hl-comment">/* 💡 ブラウザが 33.333333...% を正確に計算してくれる */</span><br>
<span class="hl-comment">/* 💡 複数演算の例: gap を引く場合などは calc((100% - 20px) / 3) のように括弧を使う */</span><br>
}
</div>
</div>.calc-math-wrapper {
background-color: #f8f9fa;
padding: 30px;
border-radius: 8px;
border: 1px solid #dee2e6;
}
.calc-demo-area {
margin-bottom: 30px;
}
/* === ❌ 罠:割り算のエラー === */
.divide-trap {
/* 🚨 エラーになる計算 */
width: calc(100% / 3%);
width: 100%; /* ※表示担保 */
background-color: #dc3545;
color: #ffffff;
padding-top: 10px;
padding-bottom: 10px;
font-weight: bold;
text-align: center;
}
/* === ⭕️ 成功:正確な3等分 === */
.divide-container {
display: flex;
width: 100%;
border: 1px solid #ccc;
}
.divide-box {
/* 💡 単位なしで割る */
width: calc(100% / 3);
background-color: #198754;
color: #ffffff;
padding-top: 15px;
padding-bottom: 15px;
font-weight: bold;
text-align: center;
border-right: 1px solid #ffffff;
}
.divide-box:last-child {
border-right: none;
}
/* =コード解説エリア(エディタ風)= */
.calc-code-area {
background-color: #282c34;
color: #abb2bf;
padding: 20px;
border-radius: 6px;
font-family: monospace;
font-size: 13px;
line-height: 1.6;
border-left-style: solid;
border-left-width: 4px;
border-left-color: #0d6efd;
overflow-x: auto;
text-align: left;
}
.hl-blue { color: #61afef; font-weight: bold; }
.hl-red { color: #e06c75; font-weight: bold; }
.hl-green { color: #98c379; font-weight: bold; }
.hl-comment { color: #6c757d; font-style: italic; }calc()を使っていて最も多く、最も初歩的なミスでありながらたまにやってしまうのがcalc()が効かない)の原因の第1位である「スペースの罠」です。
効かないバグを防ぐには、calc()の中で演算子(特に+と-)を書くときは、前後に半角スペースを1つずつ入れることです。(例:calc(100% - 20px))
掛け算や割り算はスペースがなくても動くが、可読性のために四則演算すべてにおいて『数値 スペース 記号 スペース 数値』のフォーマットで記述する癖をつけることです。
⭕️ 初心者が絶対ハマる罠!「-」と「+」の前後は必ず半角スペースを空けろ!
❌ 罠(スペースなし)
※マイナスが数値にくっついているため、
計算が無効になっています。
⭕️ 成功(スペースあり)
※正しく計算され、親要素から
20pxだけ短いバーが完成しました。
<div class="calc-space-wrapper">
<p class="calc-caption">⭕️ 初心者が絶対ハマる罠!「-」と「+」の前後は必ず半角スペースを空けろ!</p>
<div class="calc-demo-area">
<div class="calc-trap-box">
<p class="demo-title is-error">❌ 罠(スペースなし)</p>
<div class="space-trap-bar">
calc(100%-20px)
</div>
<p class="demo-desc">※マイナスが数値にくっついているため、<br>計算が無効になっています。</p>
</div>
<div class="calc-success-box">
<p class="demo-title is-success">⭕️ 成功(スペースあり)</p>
<div class="space-success-bar">
calc(100% - 20px)
</div>
<p class="demo-desc">※正しく計算され、親要素から<br>20pxだけ短いバーが完成しました。</p>
</div>
</div>
<div class="calc-code-area">
<span class="hl-comment">/* ❌ 罠:マイナス記号がくっついている(負の数と誤認される) */</span><br>
<span class="hl-blue">.space-trap-bar</span> {<br>
<span class="hl-green">width:</span> <span class="hl-red">calc(100%-20px);</span> <span class="hl-comment">/* 🚨 エラー!ブラウザはこれを計算式と認めない */</span><br>
}<br><br>
<span class="hl-comment">/* ⭕️ 演算子の前後には必ず「半角スペース」を入れる! */</span><br>
<span class="hl-blue">.space-success-bar</span> {<br>
<span class="hl-green">width:</span> <span class="hl-red">calc(100% - 20px);</span> <span class="hl-comment">/* 💡 これで完璧に動作する */</span><br>
}
</div>
</div>.calc-space-wrapper {
background-color: #f8f9fa;
padding: 30px;
border-radius: 8px;
border: 1px solid #dee2e6;
}
/* === ❌ 罠:スペースなし === */
.space-trap-bar {
/* 🚨 エラーになる計算(スペースなし) */
width: calc(100%-20px);
width: 100%; /* ※表示担保 */
background-color: #dc3545;
color: #ffffff;
padding-top: 10px;
padding-bottom: 10px;
font-weight: bold;
text-align: center;
}
/* === ⭕️ 成功:スペースあり === */
.space-success-bar {
/* 💡 正しい計算(前後に半角スペース) */
width: calc(100% - 20px);
background-color: #198754;
color: #ffffff;
padding-top: 10px;
padding-bottom: 10px;
font-weight: bold;
text-align: center;
}
/* =コード解説エリア(エディタ風)= */
.calc-code-area {
background-color: #282c34;
color: #abb2bf;
padding: 20px;
border-radius: 6px;
font-family: monospace;
font-size: 13px;
line-height: 1.6;
border-left-style: solid;
border-left-width: 4px;
border-left-color: #0d6efd;
overflow-x: auto;
text-align: left;
}
.hl-blue { color: #61afef; font-weight: bold; }
.hl-red { color: #e06c75; font-weight: bold; }
.hl-green { color: #98c379; font-weight: bold; }
.hl-comment { color: #6c757d; font-style: italic; }CSSのcalc()関数は、単なる数値計算ツールにとどまりません。
近年のWeb開発において、異なる単位を組み合わせた柔軟なレイアウト構築に必要不可欠なコア技術となっています。
ここでは、幅と高さの計算、ビューポート(画面サイズ)に合わせた動的な余白調整、絶対配置(position)の精密なコントロールまで解説します。
実務において最も登場頻度が高いのが、幅の計算や高さの計算です。
画面全体100%を基準に、サイドバーやアイコンの固定幅分だけをマイナスする100% - 50pxの計算は、レスポンシブデザインの基礎中の基礎です。
また、カード型レイアウトなどで要素を3分割する際にも、calc(100% / 3)の割り算が活躍します。
レイアウト分割では、隙間(gap)を含むカラム分割を行う際、『全体の幅(100%)から隙間の合計ピクセル数を引く』ことです。
3分割で隙間が2箇所(20px × 2 = 40px)あるなら、calc((100% - 40px) / 3)と記述します。
これにより、どんな画面幅でも1pxの狂いなく3分割レイアウトが完成します。
⭕️ 画面幅を変えて確認!gap(隙間)の合計を引いてから割るのが鉄則!
❌ 罠(カラム落ち)
※gapの幅を無視して calc(100% / 3) としたため、
はみ出して3つ目が下に落ちます。
⭕️ 成功(完璧な3分割)
※全体の100%からgap2つ分(40px)を引き、
その残りを3等分しています。
<div class="layout-calc-wrapper">
<p class="calc-caption">⭕️ 画面幅を変えて確認!gap(隙間)の合計を引いてから割るのが鉄則!</p>
<div class="calc-demo-area">
<div class="demo-layout-box">
<p class="demo-title is-error">❌ 罠(カラム落ち)</p>
<div class="trap-flex-container">
<div class="trap-col">1</div>
<div class="trap-col">2</div>
<div class="trap-col">3</div>
</div>
<p class="demo-desc">※gapの幅を無視して calc(100% / 3) としたため、<br>はみ出して3つ目が下に落ちます。</p>
</div>
<div class="demo-layout-box">
<p class="demo-title is-success">⭕️ 成功(完璧な3分割)</p>
<div class="success-flex-container">
<div class="success-col">1</div>
<div class="success-col">2</div>
<div class="success-col">3</div>
</div>
<p class="demo-desc">※全体の100%からgap2つ分(40px)を引き、<br>その残りを3等分しています。</p>
</div>
</div>
<div class="calc-code-area">
<span class="hl-comment">/* ❌ 罠:20pxの隙間があるのに、100%をそのまま3で割ってしまう */</span><br>
<span class="hl-blue">.trap-flex-container</span> {<br>
<span class="hl-green">display:</span> <span class="hl-red">flex;</span><br>
<span class="hl-green">gap:</span> <span class="hl-red">20px;</span><br>
}<br>
<span class="hl-blue">.trap-col</span> {<br>
<span class="hl-green">width:</span> <span class="hl-red">calc(100% / 3);</span> <span class="hl-comment">/* 🚨 合計が100%+40pxになり親を突き破る */</span><br>
}<br><br>
<span class="hl-comment">/* ⭕️ 隙間(gap)の合計を引いてから割る! */</span><br>
<span class="hl-blue">.success-flex-container</span> {<br>
<span class="hl-green">display:</span> <span class="hl-red">flex;</span><br>
<span class="hl-green">gap:</span> <span class="hl-red">20px;</span><br>
}<br>
<span class="hl-blue">.success-col</span> {<br>
<span class="hl-comment">/* 💡 3つの箱の間の隙間は2つ(20px × 2 = 40px)。これを引いてから3等分する */</span><br>
<span class="hl-green">width:</span> <span class="hl-red">calc((100% - 40px) / 3);</span><br>
}
</div>
</div>.layout-calc-wrapper {
background-color: #f8f9fa;
padding-top: 30px;
padding-right: 30px;
padding-bottom: 30px;
padding-left: 30px;
border-top-style: solid;
border-right-style: solid;
border-bottom-style: solid;
border-left-style: solid;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #dee2e6;
border-right-color: #dee2e6;
border-bottom-color: #dee2e6;
border-left-color: #dee2e6;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
border-bottom-left-radius: 8px;
}
.calc-caption {
font-size: 14px;
font-weight: bold;
margin-bottom: 20px;
color: #198754;
text-align: center;
}
/* 💡 修正:外側のデモエリアを、強力な「CSS Grid」で確実に2分割する */
.calc-demo-area {
display: grid;
grid-template-columns: 1fr 1fr; /* 確実に1対1の2カラムにする */
gap: 30px; /* デモボックス間の隙間 */
background-color: #e9ecef;
padding-top: 40px;
padding-right: 20px;
padding-bottom: 40px;
padding-left: 20px;
border-top-style: dashed;
border-right-style: dashed;
border-bottom-style: dashed;
border-left-style: dashed;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #adb5bd;
border-right-color: #adb5bd;
border-bottom-color: #adb5bd;
border-left-color: #adb5bd;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
border-bottom-left-radius: 8px;
margin-bottom: 40px;
}
.demo-layout-box {
background-color: #ffffff;
padding-top: 20px;
padding-right: 20px;
padding-bottom: 20px;
padding-left: 20px;
border-top-style: solid;
border-right-style: solid;
border-bottom-style: solid;
border-left-style: solid;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #ced4da;
border-right-color: #ced4da;
border-bottom-color: #ced4da;
border-left-color: #ced4da;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
text-align: center;
width: 100%;
box-sizing: border-box;
}
.demo-title {
margin-top: 0;
margin-bottom: 15px;
font-size: 14px;
font-weight: bold;
}
.is-error { color: #dc3545; }
.is-success { color: #198754; }
.demo-desc {
margin-top: 20px;
margin-bottom: 0;
font-size: 11px;
color: #6c757d;
line-height: 1.6;
}
/* === ❌ 罠:カラム落ちするFlexbox === */
.trap-flex-container {
display: flex;
flex-wrap: wrap;
gap: 20px;
background-color: #f1f3f5;
padding-top: 10px;
padding-right: 10px;
padding-bottom: 10px;
padding-left: 10px;
box-sizing: border-box;
}
.trap-col {
width: calc(100% / 3);
background-color: #dc3545;
color: #ffffff;
padding-top: 15px;
padding-bottom: 15px;
font-weight: bold;
text-align: center;
box-sizing: border-box;
}
/* === ⭕️ 成功:完璧な3等分Flexbox === */
.success-flex-container {
display: flex;
flex-wrap: wrap;
gap: 20px;
background-color: #f1f3f5;
padding-top: 10px;
padding-right: 10px;
padding-bottom: 10px;
padding-left: 10px;
box-sizing: border-box;
}
.success-col {
width: calc((100% - 40px) / 3);
background-color: #198754;
color: #ffffff;
padding-top: 15px;
padding-bottom: 15px;
font-weight: bold;
text-align: center;
box-sizing: border-box;
}
/* =コード解説エリア(エディタ風)= */
.calc-code-area {
background-color: #282c34;
color: #abb2bf;
padding-top: 20px;
padding-right: 20px;
padding-bottom: 20px;
padding-left: 20px;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
border-bottom-right-radius: 6px;
border-bottom-left-radius: 6px;
font-family: monospace;
font-size: 13px;
line-height: 1.6;
border-left-style: solid;
border-left-width: 4px;
border-left-color: #0d6efd;
overflow-x: auto;
text-align: left;
}
.hl-blue { color: #61afef; font-weight: bold; }
.hl-red { color: #e06c75; font-weight: bold; }
.hl-green { color: #98c379; font-weight: bold; }
.hl-comment { color: #6c757d; font-style: italic; }
/* 💡 スマホ等で画面が狭くなった場合は、自動で縦並びに戻す */
@media screen and (max-width: 767px) {
.calc-demo-area {
grid-template-columns: 1fr;
}
}要素の性質を決めるflexや隙間を作るgapについて詳しく知りたい人は以下から一読ください。
ブラウザの表示領域(ビューポート)を基準にする単位であるvwやvhは、calc()と組み合わせることで絶大な威力を発揮します。
最も定番なのが、ファーストビュー(サイトを開いて最初に目に入る領域)を全画面表示にしたい時です。
画面上部に固定ヘッダーがある場合、そのままheight: 100vh;にしてしまうと、ヘッダーの高さの分だけ要素が下に押し出されてしまい、画面から見切れてスクロールバーが発生してしまいます。
そこでcalc()を使い、「画面の高さからヘッダーの高さを引く」ことでピッタリと収めます。
ビューポート単位は、幅を画面いっぱいにしたい時、スクロールバーの罠を避けるために100vwではなく100%を使うことです。
一方、高さを画面いっぱいにしつつヘッダーを避ける場合は、min-height: calc(100vh - 80px);のように計算させ、画面にピッタリ収まるヒーロー領域(メインビジュアル)を作ることです。
⭕️ 固定ヘッダーの下に「画面ピッタリ」のビジュアルを作るなら vh – px だ!
<div class="viewport-calc-wrapper">
<p class="calc-caption">⭕️ 固定ヘッダーの下に「画面ピッタリ」のビジュアルを作るなら vh - px だ!</p>
<div class="calc-demo-area">
<div class="pseudo-browser">
<header class="demo-header">
高さ40pxの固定ヘッダー
</header>
<div class="hero-section">
calc(100vh - 40px)<br>
<span style="font-size: 11px;">※デモのため、ここでは 100% を基準に計算しています</span>
</div>
</div>
</div>
<div class="calc-code-area">
<span class="hl-comment">/* 💡 画面上部に固定されるヘッダー */</span><br>
<span class="hl-blue">.site-header</span> {<br>
<span class="hl-green">position:</span> <span class="hl-red">fixed;</span><br>
<span class="hl-green">top:</span> <span class="hl-red">0;</span><br>
<span class="hl-green">width:</span> <span class="hl-red">100%;</span> <span class="hl-comment">/* 🚨 100vwは横スクロールバグの元なので 100% にする */</span><br>
<span class="hl-green">height:</span> <span class="hl-red">80px;</span> <span class="hl-comment">/* ヘッダーの高さ */</span><br>
}<br><br>
<span class="hl-comment">/* ⭕️ ファーストビューをヘッダーの下にピッタリ収める */</span><br>
<span class="hl-blue">.hero-section</span> {<br>
<span class="hl-green">margin-top:</span> <span class="hl-red">80px;</span> <span class="hl-comment">/* ヘッダーの分だけ下に下げる */</span><br>
<span class="hl-comment">/* 💡 画面の高さ(100vh)から、ヘッダーの高さ(80px)を引いてピッタリ埋める */</span><br>
<span class="hl-green">min-height:</span> <span class="hl-red">calc(100vh - 80px);</span><br>
<span class="hl-green">background-color:</span> <span class="hl-red">#0d6efd;</span><br>
}
</div>
</div>.viewport-calc-wrapper {
background-color: #f8f9fa;
padding-top: 30px;
padding-right: 30px;
padding-bottom: 30px;
padding-left: 30px;
border-top-style: solid;
border-right-style: solid;
border-bottom-style: solid;
border-left-style: solid;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #dee2e6;
border-right-color: #dee2e6;
border-bottom-color: #dee2e6;
border-left-color: #dee2e6;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
border-bottom-left-radius: 8px;
}
.calc-caption {
font-size: 14px;
font-weight: bold;
margin-bottom: 20px;
color: #198754;
text-align: center;
}
.calc-demo-area {
display: flex;
justify-content: center;
background-color: #e9ecef;
padding-top: 40px;
padding-right: 20px;
padding-bottom: 40px;
padding-left: 20px;
border-top-style: dashed;
border-right-style: dashed;
border-bottom-style: dashed;
border-left-style: dashed;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #adb5bd;
border-right-color: #adb5bd;
border-bottom-color: #adb5bd;
border-left-color: #adb5bd;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
border-bottom-left-radius: 8px;
margin-bottom: 40px;
}
/* デモ用の擬似ブラウザ領域 */
.pseudo-browser {
width: 100%;
max-width: 400px;
height: 250px;
/* 💡 確実な中央寄せのための指定 */
margin-top: 0;
margin-right: auto;
margin-bottom: 0;
margin-left: auto;
background-color: #ffffff;
border-top-style: solid;
border-right-style: solid;
border-bottom-style: solid;
border-left-style: solid;
border-top-width: 2px;
border-right-width: 2px;
border-bottom-width: 2px;
border-left-width: 2px;
border-top-color: #adb5bd;
border-right-color: #adb5bd;
border-bottom-color: #adb5bd;
border-left-color: #adb5bd;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
border-bottom-right-radius: 6px;
border-bottom-left-radius: 6px;
overflow: hidden;
display: flex;
flex-direction: column;
}
.demo-header {
background-color: #212529;
color: #ffffff;
height: 40px; /* デモ用ヘッダー高 */
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: bold;
}
.hero-section {
/* 💡 デモ環境なので100%から引いています(実務では100vh) */
height: calc(100% - 40px);
background-color: #0d6efd;
color: #ffffff;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 16px;
text-align: center;
line-height: 1.5;
}
/* =コード解説エリア(エディタ風)= */
.calc-code-area {
background-color: #282c34;
color: #abb2bf;
padding-top: 20px;
padding-right: 20px;
padding-bottom: 20px;
padding-left: 20px;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
border-bottom-right-radius: 6px;
border-bottom-left-radius: 6px;
font-family: monospace;
font-size: 13px;
line-height: 1.6;
border-left-style: solid;
border-left-width: 4px;
border-left-color: #0d6efd;
overflow-x: auto;
text-align: left;
}
.hl-blue { color: #61afef; font-weight: bold; }
.hl-red { color: #e06c75; font-weight: bold; }
.hl-green { color: #98c379; font-weight: bold; }
.hl-comment { color: #6c757d; font-style: italic; }幅(width)や高さ(height)の設定について詳しく知りたい人は以下から一読ください。
要素を自由な位置に配置する絶対配置(position: absolute;)や背景画像の配置においても、calc()は神業的な力を発揮します。
例えば、「画面の左から50%(中央)に進んだ位置から、さらに自分の幅の半分だけ左に戻る」という計算をleft: calc(50% - 150px);のように行えば、要素を中央寄せできます。
※現在はtransform: translate(-50%, -50%)が主流ですが、古い手法として今でもコード内で見かけます。
同じように上部からの距離の制御も可能です。
位置指定は、右下から少し離した配置(絶対配置や背景)を行いたい場合、HTMLを汚さずにrightやbackground-positionにcalc()を直接指定することです。
例えば背景画像ならbackground-position: calc(100% - 20px) calc(100% - 20px);とするだけで、右下から正確に20px浮かせた位置にアイコン等を一発で配置できます。
⭕️ HTMLを無駄に増やすな!位置の微調整は calc() の一撃で仕留めろ!
※右上のバッジは position: absolute; で
「右から -10px」「上から -10px」の
はみ出した位置に配置しています。
※右下のアイコンは background-position で
「右下から 100% – 15px」の位置に
背景画像として描画しています。
<div class="position-calc-wrapper">
<p class="calc-caption">⭕️ HTMLを無駄に増やすな!位置の微調整は calc() の一撃で仕留めろ!</p>
<div class="calc-demo-area">
<div class="position-demo-container">
<div class="badge-absolute">
NEW
</div>
<p class="demo-desc" style="margin-top: 50px;">
※右上のバッジは position: absolute; で<br>
「右から -10px」「上から -10px」の<br>
はみ出した位置に配置しています。
</p>
<p class="demo-desc" style="margin-top: 20px;">
※右下のアイコンは background-position で<br>
「右下から 100% - 15px」の位置に<br>
背景画像として描画しています。
</p>
</div>
</div>
<div class="calc-code-area">
<span class="hl-comment">/* === 💡 1. 絶対配置(position)の微調整 === */</span><br>
<span class="hl-blue">.badge-absolute</span> {<br>
<span class="hl-green">position:</span> <span class="hl-red">absolute;</span><br>
<span class="hl-green">top:</span> <span class="hl-red">calc(0% - 10px);</span> <span class="hl-comment">/* 💡 上端からさらに10px上に飛び出させる */</span><br>
<span class="hl-green">right:</span> <span class="hl-red">calc(0% - 10px);</span> <span class="hl-comment">/* 💡 右端からさらに10px右に飛び出させる */</span><br>
}<br><br>
<span class="hl-comment">/* === ⭕️ 背景画像(background)の微調整 === */</span><br>
<span class="hl-blue">.position-demo-container</span> {<br>
<span class="hl-green">background-image:</span> <span class="hl-red">url('icon.svg');</span><br>
<span class="hl-green">background-repeat:</span> <span class="hl-red">no-repeat;</span><br>
<span class="hl-comment">/* 💡 横位置:右端(100%)から左へ15px戻る */</span><br>
<span class="hl-comment">/* 💡 縦位置:下端(100%)から上へ15px戻る */</span><br>
<span class="hl-green">background-position:</span> <span class="hl-red">calc(100% - 15px) calc(100% - 15px);</span><br>
}
</div>
</div>.position-calc-wrapper {
background-color: #f8f9fa;
padding-top: 30px;
padding-right: 30px;
padding-bottom: 30px;
padding-left: 30px;
border-top-style: solid;
border-right-style: solid;
border-bottom-style: solid;
border-left-style: solid;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #dee2e6;
border-right-color: #dee2e6;
border-bottom-color: #dee2e6;
border-left-color: #dee2e6;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
border-bottom-left-radius: 8px;
}
.position-demo-container {
margin-top: 0;
margin-right: auto;
margin-bottom: 0;
margin-left: auto;
background-color: #ffffff;
padding-top: 30px;
padding-right: 20px;
padding-bottom: 30px;
padding-left: 20px;
border-top-style: solid;
border-right-style: solid;
border-bottom-style: solid;
border-left-style: solid;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #ced4da;
border-right-color: #ced4da;
border-bottom-color: #ced4da;
border-left-color: #ced4da;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
border-bottom-right-radius: 6px;
border-bottom-left-radius: 6px;
width: 100%;
max-width: 350px;
position: relative; /* バッジの基準点 */
/* 💡 デモ用の背景設定(ダミーアイコンとしてSVGを使用) */
background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2230%22%20height%3D%2230%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22%23198754%22%3E%3Cpath%20d%3D%22M12%200c-6.627%200-12%205.373-12%2012s5.373%2012%2012%2012%2012-5.373%2012-12-5.373-12-12-12zm-1%2017l-5-5%201.414-1.414%203.586%203.586%207.586-7.586%201.414%201.414-9%209z%22%2F%3E%3C%2Fsvg%3E");
background-repeat: no-repeat;
/* ⭕️ background-positionでのcalc活用 */
/* X: 100%から左へ15px, Y: 100%から上へ15px */
background-position-x: calc(100% - 15px);
background-position-y: calc(100% - 15px);
}
/* 💡 絶対配置(position)でのcalc活用 */
.badge-absolute {
position: absolute;
/* 上と右からそれぞれ10pxはみ出させる */
top: calc(0% - 10px);
right: calc(0% - 10px);
background-color: #dc3545;
color: #ffffff;
padding-top: 5px;
padding-right: 10px;
padding-bottom: 5px;
padding-left: 10px;
border-top-left-radius: 20px;
border-top-right-radius: 20px;
border-bottom-right-radius: 20px;
border-bottom-left-radius: 20px;
font-size: 12px;
font-weight: bold;
}
/* =コード解説エリア(エディタ風)= */
.calc-code-area {
background-color: #282c34;
color: #abb2bf;
padding-top: 20px;
padding-right: 20px;
padding-bottom: 20px;
padding-left: 20px;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
border-bottom-right-radius: 6px;
border-bottom-left-radius: 6px;
font-family: monospace;
font-size: 13px;
line-height: 1.6;
border-left-style: solid;
border-left-width: 4px;
border-left-color: #0d6efd;
overflow-x: auto;
text-align: left;
}
.hl-blue { color: #61afef; font-weight: bold; }
.hl-red { color: #e06c75; font-weight: bold; }
.hl-green { color: #98c379; font-weight: bold; }
.hl-comment { color: #6c757d; font-style: italic; }様々な要素の中央寄せや絶対配置について詳しく知りたい人は以下から一読ください。
CSSのcalc()を使いこなすようになると、次に誰もがぶつかる壁が「他の要素のサイズを使って計算できないか?」という疑問です。
動的なレイアウトを構築する際、変数を扱うようにcalc()を活用できれば、計算の自由度は向上します。
しかし、CSSはプログラミング言語(JavaScriptなど)とは異なるため、値の取得や連携において独特の仕様と限界が存在します。
ここでは、別の要素を基準にした計算の可否、実務で大活躍するCSS変数(カスタムプロパティ)との連携、多くの人がハマるattr()の罠までcalc()の高度な活用法を解説します。
attr()やcounter()との連携による高度な値の制御「隣のサイドバーの幅を自動で取得して、メインエリアの幅を計算したい」 「要素自身の幅に合わせて高さを正方形にしたい」 実務ではこういった要望が頻繁に出ます。
結論から言うと、CSSのcalc()だけでは「自分自身の現在の幅」や「他の要素の具体的なピクセル数」を直接取得して計算に組み込むことはできません。
calc()の中で使える100%は、あくまで「親要素の幅」や「親要素の高さ」の割合を示すものであり、要素自身の具体的なピクセルサイズを取得しているわけではないです。
同様に、自身の幅を基準に位置をずらしたい場合は、前章で触れたtransform: translateX(-50%)など別のアプローチが必要です。
自身の幅や他の要素のサイズに依存するレイアウトを作るには、不可能なcalc()でのサイズ取得に見切りをつけ、モダンCSSの機能で代替することです。
要素の幅に合わせて高さを変えたいならaspect-ratio: 1 / 1;(アスペクト比)を使います。
他の要素のサイズによってレイアウトを変えたいならcalc()ではなくdisplay: grid;(Gridレイアウト)の1frやautoを駆使してブラウザに自動計算させます。
⭕️ 画面幅を変えてみて!幅に合わせて高さを変えるなら calc ではなく aspect-ratio だ!
❌ 罠(高さ固定)
⭕️ 成功(正方形キープ)
<div class="calc-size-wrapper">
<p class="calc-caption">⭕️ 画面幅を変えてみて!幅に合わせて高さを変えるなら calc ではなく aspect-ratio だ!</p>
<div class="calc-demo-area">
<div class="demo-size-box">
<p class="demo-title is-error">❌ 罠(高さ固定)</p>
<div class="box-trap-size">
幅は可変だけど<br>高さは変わらない
</div>
</div>
<div class="demo-size-box">
<p class="demo-title is-success">⭕️ 成功(正方形キープ)</p>
<div class="box-success-size">
アスペクト比で<br>常に正方形!
</div>
</div>
</div>
<div class="calc-code-area">
<span class="hl-comment">/* ❌ 罠:height に calc(自身の幅) といった指定は不可能 */</span><br>
<span class="hl-blue">.box-trap-size</span> {<br>
<span class="hl-green">width:</span> <span class="hl-red">50%;</span> <span class="hl-comment">/* 親の50%の幅になるが… */</span><br>
<span class="hl-green">height:</span> <span class="hl-red">100px;</span> <span class="hl-comment">/* 🚨 高さは固定するしかなく、正方形を維持できない */</span><br>
}<br><br>
<span class="hl-comment">/* ⭕️ 幅に合わせた高さ(正方形)は aspect-ratio を使う! */</span><br>
<span class="hl-blue">.box-success-size</span> {<br>
<span class="hl-green">width:</span> <span class="hl-red">50%;</span> <span class="hl-comment">/* 幅は親の50% */</span><br>
<span class="hl-green">aspect-ratio:</span> <span class="hl-red">1 / 1;</span> <span class="hl-comment">/* 💡 これだけで、幅と同じ数値を高さに自動設定してくれる! */</span><br>
}
</div>
</div>.calc-size-wrapper {
background-color: #f8f9fa;
padding-top: 30px;
padding-right: 30px;
padding-bottom: 30px;
padding-left: 30px;
border-top-style: solid;
border-right-style: solid;
border-bottom-style: solid;
border-left-style: solid;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #dee2e6;
border-right-color: #dee2e6;
border-bottom-color: #dee2e6;
border-left-color: #dee2e6;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
border-bottom-left-radius: 8px;
}
.calc-caption {
font-size: 14px;
font-weight: bold;
margin-bottom: 20px;
color: #198754;
text-align: center;
}
.calc-demo-area {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 30px;
background-color: #e9ecef;
padding-top: 40px;
padding-right: 20px;
padding-bottom: 40px;
padding-left: 20px;
border-top-style: dashed;
border-right-style: dashed;
border-bottom-style: dashed;
border-left-style: dashed;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #adb5bd;
border-right-color: #adb5bd;
border-bottom-color: #adb5bd;
border-left-color: #adb5bd;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
border-bottom-left-radius: 8px;
margin-bottom: 40px;
}
.demo-size-box {
background-color: #ffffff;
padding-top: 20px;
padding-right: 20px;
padding-bottom: 20px;
padding-left: 20px;
border-top-style: solid;
border-right-style: solid;
border-bottom-style: solid;
border-left-style: solid;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #ced4da;
border-right-color: #ced4da;
border-bottom-color: #ced4da;
border-left-color: #ced4da;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
text-align: center;
width: 100%;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
}
.demo-title {
margin-top: 0;
margin-bottom: 15px;
font-size: 14px;
font-weight: bold;
}
.is-error { color: #dc3545; }
.is-success { color: #198754; }
/* === ❌ 罠:高さ固定 === */
.box-trap-size {
width: 50%;
height: 100px;
background-color: #dc3545;
color: #ffffff;
display: flex;
justify-content: center;
align-items: center;
font-size: 12px;
font-weight: bold;
text-align: center;
}
/* === ⭕️ 成功:aspect-ratio === */
.box-success-size {
width: 50%;
aspect-ratio: 1 / 1;
background-color: #198754;
color: #ffffff;
display: flex;
justify-content: center;
align-items: center;
font-size: 12px;
font-weight: bold;
text-align: center;
}
/* =コード解説エリア(エディタ風)= */
.calc-code-area {
background-color: #282c34;
color: #abb2bf;
padding-top: 20px;
padding-right: 20px;
padding-bottom: 20px;
padding-left: 20px;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
border-bottom-right-radius: 6px;
border-bottom-left-radius: 6px;
font-family: monospace;
font-size: 13px;
line-height: 1.6;
border-left-style: solid;
border-left-width: 4px;
border-left-color: #0d6efd;
overflow-x: auto;
text-align: left;
}
.hl-blue { color: #61afef; font-weight: bold; }
.hl-red { color: #e06c75; font-weight: bold; }
.hl-green { color: #98c379; font-weight: bold; }
.hl-comment { color: #6c757d; font-style: italic; }
@media screen and (max-width: 767px) {
.calc-demo-area {
grid-template-columns: 1fr;
}
}transform・アスペクト比・Gridレイアウトについて詳しく知りたい人は以下から一読ください。
calc()の真価が発揮されるのが、CSSのカスタムプロパティ(CSS変数:--変数名)と組み合わせたテクニックです。
例えば、:rootで基準となる余白を--base-gap: 20px;と定義しておけば、要素の中でmargin-bottom: calc(var(--base-gap) * 2);のように変数を呼び出して計算できます。
また、計算式の中にさらに計算式を含める入れ子も仕様上サポートされており、複雑な数式を組むことも可能です。
変数を使った計算は、「①変数をマイナス(負の数)として扱いたい場合、calc(var(--base-gap) * -1)のように『-1を掛ける』という手法をとること。②モダンブラウザではcalc()の入れ子は単なる括弧( )として処理されるため、わざわざcalc(var(--a) + calc(10px * 2))と書かず、calc(var(--a) + (10px * 2))とシンプルに記述して可読性を高めること」です。
⭕️ 変数を制する者はレイアウトを制す!マイナスにしたい時は「* -1」だ!
❌ 罠(エラーになる)
⭕️ 成功(-1 を掛ける)
<div class="calc-var-wrapper">
<p class="calc-caption">⭕️ 変数を制する者はレイアウトを制す!マイナスにしたい時は「* -1」だ!</p>
<div class="calc-demo-area">
<div class="demo-var-box">
<p class="demo-title is-error">❌ 罠(エラーになる)</p>
<div class="box-var-base">
基準の箱
</div>
<div class="box-trap-var">
めり込ませたい箱<br>(動かない)
</div>
</div>
<div class="demo-var-box">
<p class="demo-title is-success">⭕️ 成功(-1 を掛ける)</p>
<div class="box-var-base">
基準の箱
</div>
<div class="box-success-var">
めり込ませたい箱<br>(めり込む)
</div>
</div>
</div>
<div class="calc-code-area">
<span class="hl-comment">/* 💡 基準となる変数(カスタムプロパティ)を定義 */</span><br>
<span class="hl-blue">.demo-var-box</span> {<br>
<span class="hl-green">--offset-value:</span> <span class="hl-red">30px;</span><br>
}<br><br>
<span class="hl-comment">/* ❌ 罠:変数の前に直接マイナスをつけてもエラーになる */</span><br>
<span class="hl-blue">.box-trap-var</span> {<br>
<span class="hl-green">margin-top:</span> <span class="hl-red">-var(--offset-value);</span> <span class="hl-comment">/* 🚨 無効な構文 */</span><br>
<span class="hl-comment">/* calc(-var(...)) も同様にエラーになりやすいです */</span><br>
}<br><br>
<span class="hl-comment">/* ⭕️ 変数を負の数にする時は「* -1」を使う! */</span><br>
<span class="hl-blue">.box-success-var</span> {<br>
<span class="hl-green">margin-top:</span> <span class="hl-red">calc(var(--offset-value) * -1);</span> <span class="hl-comment">/* 💡 正確に -30px として計算される */</span><br>
}
</div>
</div>.calc-var-wrapper {
background-color: #f8f9fa;
padding-top: 30px;
padding-right: 30px;
padding-bottom: 30px;
padding-left: 30px;
border-top-style: solid;
border-right-style: solid;
border-bottom-style: solid;
border-left-style: solid;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #dee2e6;
border-right-color: #dee2e6;
border-bottom-color: #dee2e6;
border-left-color: #dee2e6;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
border-bottom-left-radius: 8px;
}
.demo-var-box {
background-color: #ffffff;
padding-top: 20px;
padding-right: 20px;
padding-bottom: 20px;
padding-left: 20px;
border-top-style: solid;
border-right-style: solid;
border-bottom-style: solid;
border-left-style: solid;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #ced4da;
border-right-color: #ced4da;
border-bottom-color: #ced4da;
border-left-color: #ced4da;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
text-align: center;
width: 100%;
box-sizing: border-box;
/* 💡 CSS変数を定義 */
--offset-value: 30px;
}
.box-var-base {
background-color: #6c757d;
color: #ffffff;
padding-top: 15px;
padding-bottom: 15px;
font-weight: bold;
font-size: 13px;
position: relative;
z-index: 1;
}
/* === ❌ 罠:無効なマイナス指定 === */
.box-trap-var {
background-color: #dc3545;
color: #ffffff;
padding-top: 15px;
padding-bottom: 15px;
font-weight: bold;
font-size: 12px;
position: relative;
z-index: 0;
/* 🚨 効かない */
margin-top: -var(--offset-value);
}
/* === ⭕️ 成功:* -1 でマイナスに変換 === */
.box-success-var {
background-color: #198754;
color: #ffffff;
padding-top: 15px;
padding-bottom: 15px;
font-weight: bold;
font-size: 12px;
position: relative;
z-index: 0;
/* 💡 確実に上の要素に30pxめり込む */
margin-top: calc(var(--offset-value) * -1);
}
/* =コード解説エリア(エディタ風)= */
.calc-code-area {
background-color: #282c34;
color: #abb2bf;
padding-top: 20px;
padding-right: 20px;
padding-bottom: 20px;
padding-left: 20px;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
border-bottom-right-radius: 6px;
border-bottom-left-radius: 6px;
font-family: monospace;
font-size: 13px;
line-height: 1.6;
border-left-style: solid;
border-left-width: 4px;
border-left-color: #0d6efd;
overflow-x: auto;
text-align: left;
}
.hl-blue { color: #61afef; font-weight: bold; }
.hl-red { color: #e06c75; font-weight: bold; }
.hl-green { color: #98c379; font-weight: bold; }
.hl-comment { color: #6c757d; font-style: italic; }「HTMLに書いたカスタムデータ属性(data-xxx)の数値をCSSで取得して、calc()の計算に使いたい」
「CSSのcounter()で自動付与された連番を使って、要素ごとにずらしたアニメーションを計算したい」
HTML側から動的な数値をCSSの計算に渡すには、サポートが不十分なattr()に期待するのはやめ、HTML側のインラインスタイルとして直接『CSS変数』を渡すことです。(例:<div style="--dynamic-width: 50;">)
これを受け取り、CSS側でwidth: calc(var(--dynamic-width) * 1px);のように単位を掛け算して付与します。
これが、現状の全ブラウザで動作するHTMLからCSSへのデータ伝達手法です。
⭕️ attr() で計算はできない!HTMLから値を渡すなら「インラインCSS変数」を使え!
❌ 罠(attrは計算不可)
※attr()は文字を返すため、
calc()の中で計算できずエラーになります。
⭕️ 成功(インライン変数)
※CSS変数はcalc()で計算できるため、
後から 1% を掛けて単位を付与できます。
<div class="calc-attr-wrapper">
<p class="calc-caption">⭕️ attr() で計算はできない!HTMLから値を渡すなら「インラインCSS変数」を使え!</p>
<div class="calc-demo-area">
<div class="demo-attr-box">
<p class="demo-title is-error">❌ 罠(attrは計算不可)</p>
<div class="box-trap-attr" data-width="80">
data-width="80"
</div>
<p class="demo-desc">※attr()は文字を返すため、<br>calc()の中で計算できずエラーになります。</p>
</div>
<div class="demo-attr-box">
<p class="demo-title is-success">⭕️ 成功(インライン変数)</p>
<div class="box-success-attr" style="--html-width: 80;">
--html-width: 80
</div>
<p class="demo-desc">※CSS変数はcalc()で計算できるため、<br>後から 1% を掛けて単位を付与できます。</p>
</div>
</div>
<div class="calc-code-area">
<span class="hl-comment">/* ❌ 罠:attr() を calc の計算に使おうとしても無視される */</span><br>
<span class="hl-blue">.box-trap-attr</span> {<br>
<span class="hl-green">width:</span> <span class="hl-red">calc(attr(data-width number) * 1%);</span> <span class="hl-comment">/* 🚨 動作しない */</span><br>
<span class="hl-green">background-color:</span> <span class="hl-red">#dc3545;</span><br>
}<br><br>
<span class="hl-comment">/* ⭕️ インラインのCSS変数を受け取り、calcで単位を付与する! */</span><br>
<span class="hl-blue">.box-success-attr</span> {<br>
<span class="hl-comment">/* 💡 HTMLから渡された "--html-width: 80" という数値に、1% を掛けて幅にする */</span><br>
<span class="hl-green">width:</span> <span class="hl-red">calc(var(--html-width) * 1%);</span> <span class="hl-comment">/* 💡 結果として 80% になる */</span><br>
<span class="hl-green">background-color:</span> <span class="hl-red">#198754;</span><br>
}
</div>
</div>.calc-attr-wrapper {
background-color: #f8f9fa;
padding-top: 30px;
padding-right: 30px;
padding-bottom: 30px;
padding-left: 30px;
border-top-style: solid;
border-right-style: solid;
border-bottom-style: solid;
border-left-style: solid;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #dee2e6;
border-right-color: #dee2e6;
border-bottom-color: #dee2e6;
border-left-color: #dee2e6;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
border-bottom-left-radius: 8px;
}
.demo-attr-box {
background-color: #ffffff;
padding-top: 20px;
padding-right: 20px;
padding-bottom: 20px;
padding-left: 20px;
border-top-style: solid;
border-right-style: solid;
border-bottom-style: solid;
border-left-style: solid;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #ced4da;
border-right-color: #ced4da;
border-bottom-color: #ced4da;
border-left-color: #ced4da;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
text-align: left; /* バーを左揃えにするため */
width: 100%;
box-sizing: border-box;
}
/* === ❌ 罠:attr()による計算 === */
.box-trap-attr {
/* 🚨 効かないので初期値(または100%等)になる */
width: calc(attr(data-width number) * 1%);
/* ※表示担保のため固定値を入れています */
width: 100%;
background-color: #dc3545;
color: #ffffff;
padding-top: 10px;
padding-bottom: 10px;
font-weight: bold;
font-size: 13px;
text-align: center;
}
/* === ⭕️ 成功:インライン変数による計算 === */
.box-success-attr {
/* 💡 html側の style="--html-width: 80;" と連携 */
width: calc(var(--html-width) * 1%);
background-color: #198754;
color: #ffffff;
padding-top: 10px;
padding-bottom: 10px;
font-weight: bold;
font-size: 13px;
text-align: center;
}
/* =コード解説エリア(エディタ風)= */
.calc-code-area {
background-color: #282c34;
color: #abb2bf;
padding-top: 20px;
padding-right: 20px;
padding-bottom: 20px;
padding-left: 20px;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
border-bottom-right-radius: 6px;
border-bottom-left-radius: 6px;
font-family: monospace;
font-size: 13px;
line-height: 1.6;
border-left-style: solid;
border-left-width: 4px;
border-left-color: #0d6efd;
overflow-x: auto;
text-align: left;
}
.hl-blue { color: #61afef; font-weight: bold; }
.hl-red { color: #e06c75; font-weight: bold; }
.hl-green { color: #98c379; font-weight: bold; }
.hl-comment { color: #6c757d; font-style: italic; }プログラミング言語にあるような「もし画面幅が500px以下なら〇〇する」といった明確なif文は、CSSの仕様上存在しません。
従来はこれをメディアクエリ(@media)で条件分岐させて対応していました。
しかし、現代のCSSには条件分岐的な計算を可能にする数学関数が続々と追加されています。
ここでは、if文の代わりとして大活躍するmin()・max()・clamp()、最新ブラウザで利用可能になった絶対値や丸め処理(四捨五入など)まで解説します。
calc内で条件分岐(if/else)は可能か?min/max/clampの活用「要素の幅を基本は50vwにしたいけれど、スマホ画面では小さくなりすぎるから最低300pxは確保したい。でもPC画面では大きくなりすぎるから最大800pxで止めたい」といった細かな要望が出てきます。
このような複雑な条件を、メディアクエリを使わずに1行で解決するのがmin()・max()・clamp()です。
これらはcalc()の中でそのまま使うことも、単独で使うこともできます。
条件分岐レイアウトは、ややこしいmin()やmax()を単発で使うよりも、上限と下限を同時に設定できるclamp(最小値, 推奨値, 最大値)を積極的に使うことです。
例えばフォントサイズにfont-size: clamp(16px, 5vw, 24px);と指定すれば、『基本は画面幅の5%で可変するが、どれだけ画面が狭くても16px未満にはならず(if < 16)、どれだけ画面が広くても24px以上にはならない(else if > 24)』という条件分岐が1行で完成します。
⭕️ ウィンドウ幅を伸び縮みさせて確認!clampなら「最小・基本・最大」を1行で制御できる!
❌ 罠(限界突破)
※スマホだと細すぎて文字が溢れ、
巨大モニターだと広がりすぎます。
⭕️ 成功(clamp関数)
※基本は50%で伸縮しますが、
200px以下にも400px以上にもなりません。
<div class="math-clamp-wrapper">
<p class="calc-caption">⭕️ ウィンドウ幅を伸び縮みさせて確認!clampなら「最小・基本・最大」を1行で制御できる!</p>
<div class="calc-demo-area">
<div class="math-demo-box">
<p class="demo-title is-error">❌ 罠(限界突破)</p>
<div class="box-trap-fluid">
幅は常に 50%
</div>
<p class="demo-desc">※スマホだと細すぎて文字が溢れ、<br>巨大モニターだと広がりすぎます。</p>
</div>
<div class="math-demo-box">
<p class="demo-title is-success">⭕️ 成功(clamp関数)</p>
<div class="box-success-clamp">
200px 〜 50% 〜 400px
</div>
<p class="demo-desc">※基本は50%で伸縮しますが、<br>200px以下にも400px以上にもなりません。</p>
</div>
</div>
<div class="calc-code-area">
<span class="hl-comment">/* ❌ 罠:ただの % 指定だと、画面サイズによっては悲惨なレイアウトになる */</span><br>
<span class="hl-blue">.box-trap-fluid</span> {<br>
<span class="hl-green">width:</span> <span class="hl-red">50%;</span> <span class="hl-comment">/* 🚨 狭すぎ・広すぎに無防備 */</span><br>
}<br><br>
<span class="hl-comment">/* ⭕️ clamp(最小値, 基準値, 最大値) で完璧に制御する */</span><br>
<span class="hl-blue">.box-success-clamp</span> {<br>
<span class="hl-comment">/* 💡 画面が狭くても 200px は死守し、広くても 400px で成長を止める */</span><br>
<span class="hl-green">width:</span> <span class="hl-red">clamp(200px, 50%, 400px);</span><br>
}
</div>
</div>.math-clamp-wrapper {
background-color: #f8f9fa;
padding-top: 30px;
padding-right: 30px;
padding-bottom: 30px;
padding-left: 30px;
border-top-style: solid;
border-right-style: solid;
border-bottom-style: solid;
border-left-style: solid;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #dee2e6;
border-right-color: #dee2e6;
border-bottom-color: #dee2e6;
border-left-color: #dee2e6;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
border-bottom-left-radius: 8px;
}
.calc-caption {
font-size: 14px;
font-weight: bold;
margin-bottom: 20px;
color: #198754;
text-align: center;
}
.calc-demo-area {
display: flex;
flex-direction: column;
gap: 30px;
background-color: #e9ecef;
padding-top: 40px;
padding-right: 20px;
padding-bottom: 40px;
padding-left: 20px;
border-top-style: dashed;
border-right-style: dashed;
border-bottom-style: dashed;
border-left-style: dashed;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #adb5bd;
border-right-color: #adb5bd;
border-bottom-color: #adb5bd;
border-left-color: #adb5bd;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
border-bottom-left-radius: 8px;
margin-bottom: 40px;
}
.math-demo-box {
background-color: #ffffff;
padding-top: 20px;
padding-right: 20px;
padding-bottom: 20px;
padding-left: 20px;
border-top-style: solid;
border-right-style: solid;
border-bottom-style: solid;
border-left-style: solid;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #ced4da;
border-right-color: #ced4da;
border-bottom-color: #ced4da;
border-left-color: #ced4da;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
width: 100%;
box-sizing: border-box;
}
.demo-title {
margin-top: 0;
margin-bottom: 15px;
font-size: 14px;
font-weight: bold;
}
.is-error { color: #dc3545; }
.is-success { color: #198754; }
/* === ❌ 罠:無防備な流動レイアウト === */
.box-trap-fluid {
width: 50%;
background-color: #dc3545;
color: #ffffff;
padding-top: 15px;
padding-bottom: 15px;
font-weight: bold;
text-align: center;
font-size: 13px;
white-space: nowrap; /* 狭くなった時の溢れ確認用 */
overflow: hidden;
text-overflow: ellipsis;
}
/* === ⭕️ 成功:clampによる防壁 === */
.box-success-clamp {
/* 💡 最小200px、基本50%、最大400px */
width: clamp(200px, 50%, 400px);
background-color: #198754;
color: #ffffff;
padding-top: 15px;
padding-bottom: 15px;
font-weight: bold;
text-align: center;
font-size: 13px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* =コード解説エリア(エディタ風)= */
.calc-code-area {
background-color: #282c34;
color: #abb2bf;
padding-top: 20px;
padding-right: 20px;
padding-bottom: 20px;
padding-left: 20px;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
border-bottom-right-radius: 6px;
border-bottom-left-radius: 6px;
font-family: monospace;
font-size: 13px;
line-height: 1.6;
border-left-style: solid;
border-left-width: 4px;
border-left-color: #0d6efd;
overflow-x: auto;
text-align: left;
}
.hl-blue { color: #61afef; font-weight: bold; }
.hl-red { color: #e06c75; font-weight: bold; }
.hl-green { color: #98c379; font-weight: bold; }
.hl-comment { color: #6c757d; font-style: italic; }min()・max()・clamp()について詳しく知りたい人は以下から一読ください。
CSSの進化は止まりません。
近年、プログラミング言語でおなじみの高度な数学関数がCSS内で直接利用できるようになりました。
例えば、マイナスの数値をプラスに変換する絶対値関数、数値を指定したステップ幅に合わせる丸め関数、平方根や累乗などです。
これらは、複雑なアニメーションの軌道計算や要素の幅を特定のピクセル単位(例:50px刻み)にスナップ(固定)させるような、高度なUI実装で威力を発揮します。
最新関数は、実務でround()やabs()を採用する場合、ターゲット層のブラウザ要件(Baselineステータス)を確認することです。
もしレガシー環境のサポートが必要なら、@supportsを使って『この関数が使えるブラウザのみ適用する』というフォールバック(代替)の記述を書き、古い環境でもサイトが壊れない安全網を張ることです。
⭕️ ウィンドウ幅を変えてみて!最新の round() を使えば、滑らかな変化を「カクカク」にできる!
💡 普通の 50%
※画面幅に合わせて、1px単位で
スムーズに幅が伸縮します。
💡 round() によるスナップ
※「50%の数値を100px単位に丸める」という
計算により、段階的に幅が変化します。
(古いブラウザでは動作しません)
<div class="math-round-wrapper">
<p class="calc-caption">⭕️ ウィンドウ幅を変えてみて!最新の round() を使えば、滑らかな変化を「カクカク」にできる!</p>
<div class="calc-demo-area">
<div class="math-demo-box">
<p class="demo-title">💡 普通の 50%</p>
<div class="box-normal-percent">
滑らかに幅が変わる
</div>
<p class="demo-desc">※画面幅に合わせて、1px単位で<br>スムーズに幅が伸縮します。</p>
</div>
<div class="math-demo-box">
<p class="demo-title is-success">💡 round() によるスナップ</p>
<div class="box-success-round">
100px 刻みでカクカク動く!
</div>
<p class="demo-desc">※「50%の数値を100px単位に丸める」という<br>計算により、段階的に幅が変化します。<br>(古いブラウザでは動作しません)</p>
</div>
</div>
<div class="calc-code-area">
<span class="hl-comment">/* 💡 比較用:通常の滑らかな幅変更 */</span><br>
<span class="hl-blue">.box-normal-percent</span> {<br>
<span class="hl-green">width:</span> <span class="hl-red">50%;</span><br>
}<br><br>
<span class="hl-comment">/* ⭕️ 最新の round() 関数を使った段階的(スナップ)レイアウト */</span><br>
<span class="hl-blue">.box-success-round</span> {<br>
<span class="hl-comment">/* 💡 古いブラウザ用の安全なフォールバック(代替) */</span><br>
<span class="hl-green">width:</span> <span class="hl-red">50%;</span><br>
<br>
<span class="hl-comment">/* 💡 round(丸め方, 対象の数値, ステップ幅) */</span><br>
<span class="hl-comment">/* ここでは「50%の幅を、一番近い100pxの倍数に切り下げる(down)」処理を行う */</span><br>
<span class="hl-green">width:</span> <span class="hl-red">round(down, 50%, 100px);</span><br>
}
</div>
</div>.math-round-wrapper {
background-color: #f8f9fa;
padding-top: 30px;
padding-right: 30px;
padding-bottom: 30px;
padding-left: 30px;
border-top-style: solid;
border-right-style: solid;
border-bottom-style: solid;
border-left-style: solid;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #dee2e6;
border-right-color: #dee2e6;
border-bottom-color: #dee2e6;
border-left-color: #dee2e6;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
border-bottom-left-radius: 8px;
}
/* === 💡 通常の幅 === */
.box-normal-percent {
width: 50%;
background-color: #6c757d;
color: #ffffff;
padding-top: 15px;
padding-bottom: 15px;
font-weight: bold;
text-align: center;
font-size: 13px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* === ⭕️ round() によるスナップ === */
.box-success-round {
/* 古いブラウザ向けのフォールバック */
width: 50%;
/* 💡 50%の幅をベースに、100px刻みで切り捨てる(スナップさせる) */
width: round(down, 50%, 100px);
background-color: #0d6efd;
color: #ffffff;
padding-top: 15px;
padding-bottom: 15px;
font-weight: bold;
text-align: center;
font-size: 13px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* =コード解説エリア(エディタ風)= */
.calc-code-area {
background-color: #282c34;
color: #abb2bf;
padding-top: 20px;
padding-right: 20px;
padding-bottom: 20px;
padding-left: 20px;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
border-bottom-right-radius: 6px;
border-bottom-left-radius: 6px;
font-family: monospace;
font-size: 13px;
line-height: 1.6;
border-left-style: solid;
border-left-width: 4px;
border-left-color: #0d6efd;
overflow-x: auto;
text-align: left;
}
.hl-blue { color: #61afef; font-weight: bold; }
.hl-red { color: #e06c75; font-weight: bold; }
.hl-green { color: #98c379; font-weight: bold; }
.hl-comment { color: #6c757d; font-style: italic; }calc()関数はレイアウト構築において無敵のツールに思えますが、実は「使える場所(プロパティ)」と「使えない場所」が厳密に定められています。
「このプロパティにもcalc()が使えるはずだ!」と推測でコードを書き、結果としてcalcが効かないという事態に直面するコーダーは少なくありません。
ここでは、フォントサイズやマージンといった定番のプロパティから、カラーやオートのような適用に落とし穴があるプロパティまで解説します。
font-size・line-height・color・autoなどへの適用の可否calc()が得意とするのは、「長さ(px, vw, %など)」や「数値」「角度」を扱うプロパティです。
しかし、初心者がよくつまずくのが、「キーワード」や「色」に対する計算です。
適用プロパティは、calc()は『数値と単位』の関数であり、キーワード(auto等)や16進数カラーコード(#fff等)には使えません。
色を動的に計算したい場合はcalc()ではなく、相対カラー構文やcolor-mix()などの『カラー専用関数』を使用します。
また、幅のキーワード計算を行いたい場合は、最新機能であるcalc-size()関数のブラウザ対応を待つ必要があります。
⭕️ 画面幅を変えて確認!「長さ」の計算は得意だが、「キーワード」は計算できない!
⭕️ 成功(長さの計算)
※フォントサイズや幅の計算は完璧に動作し、
画面幅に合わせて可変します。
❌ 罠(キーワード・色)
※autoやカラーコードは計算式に組み込めないため、
CSSが無効化されて崩れます。
<div class="calc-prop-wrapper">
<p class="calc-caption">⭕️ 画面幅を変えて確認!「長さ」の計算は得意だが、「キーワード」は計算できない!</p>
<div class="calc-demo-area">
<div class="prop-demo-box">
<p class="demo-title is-success">⭕️ 成功(長さの計算)</p>
<div class="box-success-prop">
font-size: calc(...)<br>
max-width: calc(...)
</div>
<p class="demo-desc">※フォントサイズや幅の計算は完璧に動作し、<br>画面幅に合わせて可変します。</p>
</div>
<div class="prop-demo-box">
<p class="demo-title is-error">❌ 罠(キーワード・色)</p>
<div class="box-trap-prop">
margin: calc(auto - 10px)<br>
color: calc(#fff - 10%)
</div>
<p class="demo-desc">※autoやカラーコードは計算式に組み込めないため、<br>CSSが無効化されて崩れます。</p>
</div>
</div>
<div class="calc-code-area">
<span class="hl-comment">/* ⭕️ calc() は「長さや数値」に対して使う! */</span><br>
<span class="hl-blue">.box-success-prop</span> {<br>
<span class="hl-comment">/* 💡 フォントサイズを可変にする(最小16px + 画面幅の1%) */</span><br>
<span class="hl-green">font-size:</span> <span class="hl-red">calc(16px + 1vw);</span><br>
<span class="hl-comment">/* 💡 最大幅を「100%から40px引いた値」にする */</span><br>
<span class="hl-green">max-width:</span> <span class="hl-red">calc(100% - 40px);</span><br>
<span class="hl-green">aspect-ratio:</span> <span class="hl-red">calc(16 / 9);</span> <span class="hl-comment">/* 数値のみの計算もOK(css calc aspect ratio) */</span><br>
}<br><br>
<span class="hl-comment">/* ❌ 罠:キーワードや色を計算しようとするとエラーになる */</span><br>
<span class="hl-blue">.box-trap-prop</span> {<br>
<span class="hl-green">margin-left:</span> <span class="hl-red">calc(auto - 10px);</span> <span class="hl-comment">/* 🚨 autoは数値ではないのでエラー */</span><br>
<span class="hl-green">color:</span> <span class="hl-red">calc(#000000 + 20%);</span> <span class="hl-comment">/* 🚨 色の直接計算は不可能 */</span><br>
}
</div>
</div>.calc-prop-wrapper {
background-color: #f8f9fa;
padding-top: 30px;
padding-right: 30px;
padding-bottom: 30px;
padding-left: 30px;
border-top-style: solid;
border-right-style: solid;
border-bottom-style: solid;
border-left-style: solid;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #dee2e6;
border-right-color: #dee2e6;
border-bottom-color: #dee2e6;
border-left-color: #dee2e6;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
border-bottom-left-radius: 8px;
}
.calc-caption {
font-size: 14px;
font-weight: bold;
margin-bottom: 20px;
color: #198754;
text-align: center;
}
.calc-demo-area {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 30px;
background-color: #e9ecef;
padding-top: 40px;
padding-right: 20px;
padding-bottom: 40px;
padding-left: 20px;
border-top-style: dashed;
border-right-style: dashed;
border-bottom-style: dashed;
border-left-style: dashed;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #adb5bd;
border-right-color: #adb5bd;
border-bottom-color: #adb5bd;
border-left-color: #adb5bd;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
border-bottom-left-radius: 8px;
margin-bottom: 40px;
}
.prop-demo-box {
background-color: #ffffff;
padding-top: 20px;
padding-right: 20px;
padding-bottom: 20px;
padding-left: 20px;
border-top-style: solid;
border-right-style: solid;
border-bottom-style: solid;
border-left-style: solid;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #ced4da;
border-right-color: #ced4da;
border-bottom-color: #ced4da;
border-left-color: #ced4da;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
text-align: center;
width: 100%;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
}
.demo-title {
margin-top: 0;
margin-bottom: 15px;
font-size: 14px;
font-weight: bold;
}
.is-error { color: #dc3545; }
.is-success { color: #198754; }
/* === ⭕️ 成功:長さの計算 === */
.box-success-prop {
background-color: #198754;
color: #ffffff;
padding-top: 20px;
padding-right: 20px;
padding-bottom: 20px;
padding-left: 20px;
font-weight: bold;
text-align: center;
/* 💡 font-sizeやmax-widthの計算は可能 */
font-size: calc(12px + 1vw);
max-width: calc(100% - 20px);
width: 100%;
}
/* === ❌ 罠:無効な計算 === */
.box-trap-prop {
background-color: #dc3545;
color: #ffffff;
padding-top: 20px;
padding-right: 20px;
padding-bottom: 20px;
padding-left: 20px;
font-weight: bold;
text-align: center;
font-size: 14px;
width: 100%;
/* 🚨 以下の指定は無効化されます */
margin-left: calc(auto - 10px);
color: calc(#ffffff - 20%);
}
/* =コード解説エリア(エディタ風)= */
.calc-code-area {
background-color: #282c34;
color: #abb2bf;
padding-top: 20px;
padding-right: 20px;
padding-bottom: 20px;
padding-left: 20px;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
border-bottom-right-radius: 6px;
border-bottom-left-radius: 6px;
font-family: monospace;
font-size: 13px;
line-height: 1.6;
border-left-style: solid;
border-left-width: 4px;
border-left-color: #0d6efd;
overflow-x: auto;
text-align: left;
}
.hl-blue { color: #61afef; font-weight: bold; }
.hl-red { color: #e06c75; font-weight: bold; }
.hl-green { color: #98c379; font-weight: bold; }
.hl-comment { color: #6c757d; font-style: italic; }
@media screen and (max-width: 767px) {
.calc-demo-area {
grid-template-columns: 1fr;
}
}「calc()って重くないの?」「古いスマホでもちゃんと動くの?」という疑問を持つ方もいるでしょう。
結論から言うと、基本的な四則演算を行うcalc()のブラウザサポートははるか昔のIE9時代から完了しており、現代において「対応していないブラウザ」を気にする必要は一切ありません。
また、パフォーマンスについても、ブラウザの描画エンジンはcalc()の計算を極めて高速に処理するため、何百箇所に使おうともサイトが重くなるようなことはありません。
パフォーマンスとブラウザ対応は、四則演算やmin(),max(),clamp()といった確立された関数は、パフォーマンスを気にせず使うことです。
しかし、infinityやrandom()のような最新の数学定数・関数を実務で使う場合は、『Can I Use』のサイトでサポート状況をチェックし、非対応ブラウザ向けに安全な固定値(フォールバック)を事前に記述しておくことです。
⭕️ 最新機能には罠がある!常に「非対応ブラウザ向けの安全策(フォールバック)」を用意しろ!
❌ 罠(最新機能の過信)
※非対応ブラウザではこの指定が無視され、
重なり順が初期化されてしまいます。
⭕️ 成功(フォールバック)
※先に安全な固定値を書き、
その後に最新機能を上書きで記述します。
<div class="calc-perf-wrapper">
<p class="calc-caption">⭕️ 最新機能には罠がある!常に「非対応ブラウザ向けの安全策(フォールバック)」を用意しろ!</p>
<div class="calc-demo-area">
<div class="perf-demo-box">
<p class="demo-title is-error">❌ 罠(最新機能の過信)</p>
<div class="box-trap-infinity">
z-index: calc(infinity)
</div>
<p class="demo-desc">※非対応ブラウザではこの指定が無視され、<br>重なり順が初期化されてしまいます。</p>
</div>
<div class="perf-demo-box">
<p class="demo-title is-success">⭕️ 成功(フォールバック)</p>
<div class="box-success-fallback">
安全なフォールバック
</div>
<p class="demo-desc">※先に安全な固定値を書き、<br>その後に最新機能を上書きで記述します。</p>
</div>
</div>
<div class="calc-code-area">
<span class="hl-comment">/* ❌ 罠:最先端の機能をそのまま書くと、古いSafari等で無視されて大事故になる */</span><br>
<span class="hl-blue">.box-trap-infinity</span> {<br>
<span class="hl-green">position:</span> <span class="hl-red">relative;</span><br>
<span class="hl-green">z-index:</span> <span class="hl-red">calc(infinity);</span> <span class="hl-comment">/* 🚨 非対応ブラウザでは z-index が適用されない */</span><br>
}<br><br>
<span class="hl-comment">/* ⭕️ 常に「非対応だった場合」の安全な値を直前に書く! */</span><br>
<span class="hl-blue">.box-success-fallback</span> {<br>
<span class="hl-green">position:</span> <span class="hl-red">relative;</span><br>
<span class="hl-comment">/* 💡 1. 古いブラウザ用の安全な値(フォールバック) */</span><br>
<span class="hl-green">z-index:</span> <span class="hl-red">9999;</span> <br>
<span class="hl-comment">/* 💡 2. 最新ブラウザ用の値(対応していれば上書きされる) */</span><br>
<span class="hl-green">z-index:</span> <span class="hl-red">calc(infinity);</span> <br>
}
</div>
</div>.calc-perf-wrapper {
background-color: #f8f9fa;
padding-top: 30px;
padding-right: 30px;
padding-bottom: 30px;
padding-left: 30px;
border-top-style: solid;
border-right-style: solid;
border-bottom-style: solid;
border-left-style: solid;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #dee2e6;
border-right-color: #dee2e6;
border-bottom-color: #dee2e6;
border-left-color: #dee2e6;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
border-bottom-left-radius: 8px;
}
.perf-demo-box {
background-color: #ffffff;
padding-top: 20px;
padding-right: 20px;
padding-bottom: 20px;
padding-left: 20px;
border-top-style: solid;
border-right-style: solid;
border-bottom-style: solid;
border-left-style: solid;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #ced4da;
border-right-color: #ced4da;
border-bottom-color: #ced4da;
border-left-color: #ced4da;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
text-align: center;
width: 100%;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
}
/* === ❌ 罠:最新機能の単独使用 === */
.box-trap-infinity {
background-color: #dc3545;
color: #ffffff;
padding-top: 15px;
padding-bottom: 15px;
padding-left: 10px;
padding-right: 10px;
font-weight: bold;
text-align: center;
font-size: 13px;
width: 100%;
box-sizing: border-box;
/* 🚨 最新すぎるプロパティ値 */
position: relative;
z-index: calc(infinity);
}
/* === ⭕️ 成功:フォールバックの記述 === */
.box-success-fallback {
background-color: #198754;
color: #ffffff;
padding-top: 15px;
padding-bottom: 15px;
padding-left: 10px;
padding-right: 10px;
font-weight: bold;
text-align: center;
font-size: 13px;
width: 100%;
box-sizing: border-box;
/* 💡 フォールバック(安全網) */
position: relative;
z-index: 9999;
z-index: calc(infinity);
}
/* =コード解説エリア(エディタ風)= */
.calc-code-area {
background-color: #282c34;
color: #abb2bf;
padding-top: 20px;
padding-right: 20px;
padding-bottom: 20px;
padding-left: 20px;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
border-bottom-right-radius: 6px;
border-bottom-left-radius: 6px;
font-family: monospace;
font-size: 13px;
line-height: 1.6;
border-left-style: solid;
border-left-width: 4px;
border-left-color: #0d6efd;
overflow-x: auto;
text-align: left;
}
.hl-blue { color: #61afef; font-weight: bold; }
.hl-red { color: #e06c75; font-weight: bold; }
.hl-green { color: #98c379; font-weight: bold; }
.hl-comment { color: #6c757d; font-style: italic; }
@media screen and (max-width: 767px) {
.calc-demo-area {
grid-template-columns: 1fr;
}
}分かりやすいようにまとめを記載します。
+,-,*,/)を行い、その結果をプロパティの値として動的に適用する関数。%やvwのような可変単位、pxやremなどの固定単位を混ぜて計算できる(例:calc(100% - 50px))。+)と引き算(-)を行う場合、必ず両方の数値に単位が必要。*)と割り算(/)を行う場合、少なくとも片方は「単位のない数値(数値リテラル)」にする必要がある。+と-)の前後には、必ず半角スペースを入れなければならない(エラーになるため)。( )(丸括弧)を使用して優先順位を制御する。width,height,font-size,margin,padding,top,background-positionなど「長さ・数値・角度」のプロパティに有効。auto,fit-contentなどのキーワードや、色(#fff等)を直接計算することはできない。calc()単体で「自分自身の幅」や「他要素の幅」を取得することはできない(アスペクト比等は別プロパティを使う)。var()と組み合わせて動的計算が可能。* -1を掛ける。min(),max(),clamp(最小, 基本, 最大)を使うことで、1行で高度な流動レイアウトが作れる。abs()や丸め処理round()が使用可能だが、古い環境向けのフォールバックが必須。演算子(+と-)の前後には、必ず半角スペースを空ける必要があるからです。
calc(100%-20px)のようにスペースなしで書くと、ブラウザは「マイナス20pxという負の数値」だと誤認し、計算式として成り立たなくなります。
calc(100% - 20px)のように前後に半角スペースを入れてください。
いいえ、できません。
calc()の中で使う100%などの割合は、あくまで「親要素のサイズ」を基準とするものであり、要素自身の具体的なピクセルサイズを取得する機能はありません。
幅に合わせて高さを変える(正方形などを維持する)場合は、calc()ではなくaspect-ratio: 1 / 1;を使用してください。
要素間の「隙間(gap)」の幅を計算から引き忘れていることが原因です。
例えば隙間(gap)が20pxで3つの箱を並べる場合、隙間は間に2箇所(合計40px)存在します。
そのため、単純に3で割るのではなくcalc((100% - 40px) / 3)のように、先に全体の幅から隙間の合計を引いてから割るのが正しい計算方法です。
calc()の中にはautoなどのキーワードを含めることができないからです。
calc()は「長さ・数値・角度」などを計算するための関数であり、auto、fit-contentなどの文字列キーワードや#ffffffのような色コードを直接計算することはCSSの仕様上不可能です。
calc(var(--変数名) * -1)のように、-1を掛け算してください。
-var(--変数名)やcalc(-var(--変数名))と記述すると、CSSの構文エラーとなり計算が無視されてしまいます。
変数を負の数として扱いたい場合は、「-1を掛ける」というアプローチをとるのがよいです。
サイト制作でお困りの人はお気軽にご連絡ください。
どんなお悩み事も丁寧に返信させて頂きます。
「どのサーバーを選べばいいか分からない…」そんな悩みを解決!
WordPressデビューに最適なサーバーを徹底比較しました。
