CSSのcalc()関数で要素を動的に配置する方法とは?


CSSのcalc()関数を使用すると、計算式を用いて要素のサイズや位置を動的に設定することが可能になります。従来のピクセルやパーセンテージといった静的な値ではなく、状況に応じて柔軟に値を調整できるため、レスポンシブデザインや複雑なレイアウトの構築に非常に役立ちます。

基本的な書き方

calc()関数は以下の構文で記述します。

calc( <式> )
  • 演算子の優先順位は、算数と同じように計算されます。
  • 複数の演算子を組み合わせる場合は、カッコを使って式を区切ります。
  • <式> には、数値、演算子、他の関数などを含む計算式を記述します。

使用できる値

calc()関数で使用できる値は以下の通りです。

  • 関数
    min(), max(), clamp() などの他の CSS 関数を使用できます。
  • 演算子
    足し算 (+)、引き算 (-)、掛け算 (*)、割り算 (/)、パーセンテージ (%) を使用できます。
  • 数値
    ピクセル(px)、em、remなど、あらゆる種類の数値リテラルを使用できます。

具体的な例

以下の例は、calc()関数を使用して要素の幅を動的に設定する方法を示しています。

.element {
  width: calc(50% - 20px); /* 要素の幅を50%にして、両側から20pxずつ余白を引く */
}

この例では、要素の幅が画面幅の50%になり、左右にそれぞれ20pxの余白が空きます。画面サイズが変化しても、要素の幅と余白の比率が常に維持されます。

応用例

calc()関数は、様々な場面で活用できます。以下に、いくつかの例を紹介します。

  • 複雑な装飾
    影やボーダーを計算式で生成
  • ナビゲーションメニュー
    メニューアイテムの幅を均等に配置
  • グリッドレイアウト
    列や行の幅を柔軟に設定
  • レスポンシブデザイン
    要素のサイズや位置を画面サイズに応じて調整
  • 古いブラウザでは calc()関数に対応していない場合があるため、必要に応じてベンダープレフィックスを付けて記述する必要があります。
  • 計算式が複雑になりすぎると、読みづらくなってしまうため、適切な場所でコメントを挿入するなど、可読性を意識しましょう。
  • calc()関数は、すべての CSS プロパティで使用できるわけではありません。使用できるプロパティについては、MDN Web Docsなどのリファレンスを参照してください。


.element {
  position: absolute;
  top: 50%;
  left: calc(50% - width / 2);
}

このコードでは、要素を絶対配置し、親要素の垂直方向と水平方向の中央に配置します。calc(50% - width / 2) は、要素の幅の半分をマイナスした値を計算しており、これが要素の左マージンになります。

例2:2カラムレイアウトを作成する

以下のコードは、2つの列を等幅で並べるレイアウトを作成します。

.container {
  display: flex;
}

.column {
  flex: 1;
}

このコードでは、コンテナ要素に flex プロパティを設定し、子要素を等幅で並べるようにします。各カラム要素には flex: 1 を設定することで、利用可能なスペースを均等に分配します。

例3:サイドバー付きのメインコンテンツを作成する

以下のコードは、サイドバーとメインコンテンツを持つレイアウトを作成します。サイドバーの幅は固定で、メインコンテンツは残りのスペースを占めます。

.container {
  display: flex;
}

.sidebar {
  width: 200px;
}

.main-content {
  flex: 1;
}

このコードは、例2と似ていますが、サイドバー要素に固定幅を設定しています。flex: 1 はメインコンテンツにのみ適用されるため、サイドバーの幅を引いた残りのスペースがメインコンテンツに割り当てられます。

例4:レスポンシブなナビゲーションメニューを作成する

以下のコードは、画面サイズに応じてナビゲーションメニューのアイテムを自動的に配置します。

.nav {
  display: flex;
}

.nav-item {
  flex: 1;
  text-align: center;
}

@media (max-width: 768px) {
  .nav {
    flex-direction: column;
  }

  .nav-item {
    flex: auto;
  }
}

このコードでは、ナビゲーションアイテムを横並びに配置し、それぞれが利用可能なスペースを均等に占めます。画面幅が768px以下になると、アイテムを縦並びに並べ、それぞれが自動的に折り返されるようになります。

例5:円形プログレスバーを作成する

以下のコードは、CSSだけで円形プログレスバーを作成します。

.progress-bar {
  width: 100px;
  height: 100px;
  border-radius: 50%;
  background-color: #ccc;
  overflow: hidden;
}

.progress-circle {
  width: 50%;
  height: 50%;
  border-radius: 50%;
  background-color: #007bff;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: rotate(-90deg);
}

.progress-circle::after {
  content: "";
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background-color: transparent;
  transition: transform 0.5s ease;
}

このコードは、HTMLとCSSを使用してシンプルな円形プログレスバーを作成します。calc()関数を使用して、円弧のサイズと位置を計算しています。



グリッドレイアウト

  • 欠点
    • calc() 関数ほど柔軟ではない
    • 複雑なレイアウトには向かない
  • 利点
    • レスポンシブなレイアウトを簡単に作成できる
    • コードが直感的でわかりやすい
    • 行や列の幅を柔軟に調整できる


.container {
  display: grid;
  grid-template-columns: 1fr 2fr; /* 列の幅を1:2の比率で設定 */
}

.element1 {
  grid-area: 1 / 1; /* 要素1を左上のセルに配置 */
}

.element2 {
  grid-area: 1 / 2; /* 要素2を右上のセルに配置 */
}

Flexbox

  • 欠点
    • calc() 関数ほど強力ではない
    • 複雑な計算式には向かない
  • 利点
    • 柔軟なレイアウトを簡単に作成できる
    • 要素を水平方向または垂直方向に並べることができる
    • 余白やガターを自動的に調整できる


.container {
  display: flex;
  flex-direction: row; /* 要素を横並びに配置 */
  justify-content: space-between; /* 要素を左右に均等に配置 */
}

.element1 {
  flex: 1; /* 要素1に利用可能なスペースの1割を割り当てる */
}

.element2 {
  flex: 2; /* 要素2に利用可能なスペースの2割を割り当てる */
}

変数

  • 欠点
    • 複雑な計算式には向かない
    • グリッドレイアウトやFlexboxほど強力ではない
  • 利点
    • コードを簡潔に記述できる
    • 値を後で簡単に変更できる
    • 複数の場所で同じ値を再利用できる


.container {
  width: var(--container-width); /* 変数で定義した値を使用 */
}

.element {
  width: calc(50% - var(--element-margin)); /* 変数で定義した値を使用 */
}

メディアクエリ

  • 欠点
    • 複雑なレイアウトには向かない
    • calc() 関数ほど柔軟ではない
  • 利点
    • 画面サイズに応じてレイアウトを調整できる
    • コードを簡潔に記述できる


@media (max-width: 768px) {
  .container {
    width: 100%; /* 画面幅が768px以下の場合、コンテナ要素を100%幅にする */
  }

  .element {
    width: calc(100% - 20px); /* 画面幅が768px以下の場合、要素の幅を100%にして、両側から20pxずつ余白を引く */
  }
}

JavaScript

  • 欠点
    • コードが複雑になる
    • JavaScript の知識が必要
  • 利点
    • 非常に柔軟で強力
    • 複雑な計算やアニメーションが可能


const containerWidth = document.querySelector('.container').offsetWidth;
const elementWidth = containerWidth * 0.5;

document.querySelector('.element').style.width = `${elementWidth}px`;

calc() 関数は、多くの場合において便利なツールですが、状況によっては代替方法の方が適切な場合があります。上記で紹介した代替方法を理解し、それぞれの利点と欠点を考慮して、最適な方法を選択してください。