CSSで長さを計算できるcalc()ファンクションというのはご存じですか?
ここのところ流行りのレスポンシブデザインもそうですが、コンテンツの幅をフレキシブルに対応させたいという場合に、とても役立つファンクションです。

今回はこのcalc()ファンクションの使い方や、ブラウザのサポート状況をご紹介したいと思います。

親要素の幅を超えないようにする

calc()ファンクションにはいろいろな使い方があるんですが、代表的なところで言えば画像などのコンテンツ幅が親要素の幅を超えないようにするという使い方。

通常、コンテンツ幅をフレキシブルに対応させるだけなら、CSSのmax-widthプロパティに対して100%と値を指定すりゃいいわけです。

しかし、ここにpaddingborderといったプロパティを与えた途端に、親要素の幅をサラリと超えてきやがります。子の成長が著しい。

コンテンツ幅が親要素を超える例paddingを与えた画像にmax-width: 100%;を指定。親要素よりも幅が大きい。

そこで親要素の幅を超えないよう、calc()ファンクションを使って100%からpadding分の数値を差し引いてやります。

img {
	max-width: calc(100% - 8px*2);
	padding: 8px;
}

これで100%から一辺あたりにpaddingとして指定した8pxを左右二辺分掛けた数値が差し引かれるということになります。
つまり、親要素の幅から画像の左右のpaddingの大きさを計算して引き算し、その解となる数値が画像の最大幅として与えられたというわけ。

calc()ファンクションのいいところは、%emvwなどの異なる単位同士でもちゃんと計算して解を出し適用できるという点。
いちいち予め計算して幅を割り出すなど、面倒な手間も軽減されます。

上記の例について、はてブのコメントで「box-sizing使えば解決するよね」っていうコメントがあったので以下捕捉。

親要素の幅を子要素が超えてしまうという状況を解決する方法として、box-sizingプロパティを用いるという方法があります。

img {
	max-width: 100%;
	padding: 8px;
	box-sizing: border-box;
}

CSSに書くならこんな感じ。

確かにこれでも子要素の幅が親要素を超えることはなくなるんですが、この方法にはちと盲点があります。
というのも、box-sizingプロパティを与えることでimg要素のwidth属性とheight属性にも影響を与えてしまいます。

どういうことが起きるかというと、マークアップで指定している値と、実際に表示される大きさが異なってしまうんですね。
Retinaディスプレイを考慮して記事中に縦横2倍の画像を入れたときなどに計算が狂ったりとか。

このあたりを未然に防ぐ意味でも、box-sizingではなくcalc()ファンクションをオススメします。

各ブラウザのサポート状況

calc()ファンクションのブラウザサポート状況は以下のとおり。

  • Internet Explorer
    IE9からサポート。
  • Firefox
    Firefox4〜15までベンダープレフィックス付きで先行実装。
    Firefox16からサポート。
  • Google Chrome
    Chrome19〜25までベンダープレフィックス付きで先行実装。
    Chrome26からサポート。
  • Safari
    Safari6.0からベンダープレフィックス付きで先行実装。
    Safari6.1及びSafari7.0からサポート。
  • iOS
    iOS 6.0から6.1までベンダープレフィックス付きで先行実装。
    iOS 7からサポート。
  • Android
    Android 4.4からサポート。

見てもらえればわかるように、ごくごく最近になってようやくほぼサポートされてきたかなーという感じです。
とは言え、ユーザーのブラウザ利用状況を考えれば、まだベンダープレフィックスを付けつつ、非対応のブラウザに対するフォールバックは欠かせないと言えます。とりあえずIEは爆発しろ。

なので、先ほどの例をベンダープレフィックス付き、かつフォールバックしたものにすると以下のようになります。

img {
	max-width: 90%;
	max-width: -webkit-calc(100% - 8px*2);
	max-width: -moz-calc(100% - 8px*2);
	max-width: calc(100% - 8px*2);
	padding: 8px;
}

レイアウトが破綻しないくらいのざっくりした数値をフォールバックとして指定しておきましょう。

ベンダープレフィックスはプロパティではなくcalc()ファンクションに付けます。間違わないように注意。
-moz-はもう別にいらないかもしれませんけど念のためってことで。

こんなプロパティにも calc() は使える!

今回の例では最大幅を指定するためのmax-widthプロパティをベースに説明しましたが、他にも様々なプロパティに対して使うことができます。

  • width
  • height
  • margin
  • padding
  • font-size
  • background-position
  • text-shadow
  • transform:rotate()

などなど、長さや周波数、角度、数量、時間、整数値に当てはまる値を用いるプロパティであれば、どこでも使うことができます。

また、calc()ファンクションの中でさらに別のcalc()ファンクションを使うといったことも可能。

使い方次第で、これまでちょっと難しかったレイアウトがかなり簡単にできるようになるので、ぜひCSSにうまく導入してみてください。

Commentsコメントしてもらえると励みになります