CSSのcalc()関数を使うとスゴイ便利!ページのレイアウト、要素やフォントのサイズ指定など実装テクニックのまとめ
Post on:2017年2月9日
pxでも、%, em, rem, vw, vhなどの相対単位でも、異なる単位の計算式で値を指定できる「calc()」がどのように機能し、どのように使うのか、「calc()」を使うと便利になる要素のセンタリング、フォントサイズ、グリッドの作成などの実装例を紹介します。
Opera Miniを除くすべてのメジャーブラウザに「calc()」はサポートされており、レスポンシブとも非常に相性のよいCSSの関数です。
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
「calc()」とは値を計算式で指定できる
CSS3の「calc()」は、プロパティの値を計算式で実行することができます。例えば、要素の幅をpx値で指定する代わりに、2つ以上の数値を加算した結果を指定するために「calc()」を使用できます。
1 2 3 |
.foo { width: calc(100px + 50px); } |
「calc()」を使う理由
SassのようなCSSプリプロセッサを使用した時に、下記のような記述をすることがあります。
1 2 3 4 5 6 7 8 9 10 |
.foo { width: 100px + 50px; } // またはSassの変数を使用 $width-one: 100px; $width-two: 50px; .bar { width: $width-one + $width-two; } |
このような時に、「calc()」は2つの理由でより良い解決方法を提供します。
1つ目の理由は、異なる単位で計算することができます。具体的には、相対単位(%やvw, vhなど)と絶対単位(pxなど)を組み合わせることができます。
例えば、%からpxを減算する計算式を値として指定できます。
1 2 3 |
.foo { width: calc(100% - 50px); } |
この例では幅いっぱい(100%)から、50pxの固定幅を引いた数値を指定しています。サイドバーのレイアウトなどによく使う記述です。
2つ目の理由は、「calc()」は計算された値は計算式自体であり、結果の値ではないということです。CSSプリプロセッサで計算式を扱う場合、ブラウザに与えられる値は式の結果の値です。
1 2 3 4 5 6 7 8 9 |
// SCSSで指定された値 .foo { width: 100px + 50px; } // ブラウザでCSSと計算値をコンパイル .foo { width: 150px; } |
しかし、「calc()」ではブラウザによって解析された値が実際の「calc()」の計算式です。
1 2 3 4 5 6 7 8 9 |
// CSSで指定された値 .foo { width: calc(100% - 50px); } // ブラウザの計算値 .foo { width: calc(100% - 50px); } |
これはブラウザにおける値がより動的になり、ビューポートの変更に合わせて適応できることを意味します。例えば、ビューポートの高さから絶対値を引いた要素をビューポートの変更に合わせて適応させることができます。
「calc()」の使い方
「calc()」は、数値指定するプロパティの値に加算、減算、乗算、除算式で指定できます。データタイプは <length>, <frequency>, <angle>, <time>, <number>, <integer> です。
いくつか例をあげておきます。
1 2 3 4 5 6 7 |
.foo { width: calc(50vmax + 3rem); padding: calc(1vw + 1em); transform: rotate( calc(1turn + 28deg) ); background: hsl(100, calc(3 * 20%), 40%); font-size: calc(50vw / 3); } |
「calc()」の入れ子
「calc()」の計算式は、入れ子で利用できます。ただし、内部関数は単純なかっこ式として扱われます。
「calc()」の入れ子の計算式は、下記のようになります。
1 2 3 |
.foo { width: calc( 100% / calc(100px * 2) ); } |
上記の「calc()」の入れ子の計算式の計算値は下記のようになります。
1 2 3 |
.foo { width: calc( 100% / (100px * 2) ); } |
フォールバックの提供
「calc()」のサポートブラウザは、かなり増えました。
Opera Miniを除くすべてのメジャーブラウザにサポートされています。
「calc()」をサポートしていないブラウザでは、プロパティ値の式全体が無視されます。そのため、非サポートのブラウザで使用されるフォールバックを静的な値で提供しておくとよいでしょう。
1 2 3 4 |
.foo { width: 90%; /* 非サポートブラウザ用のフォールバック */ width: calc(100% - 50px); } |
「calc()」を使うと便利になる実装テクニック
「calc()」はさまざまな状況で役に立ちます。
「calc()」の実装例: 要素のセンタリング
「calc()」は、要素をコンテナ内で天地と左右の中央にセンタリングするという古くからの問題に簡単に対応できます。「calc()」無しで実装する場合、子要素のサイズが分かっていれば、負のマージンで要素を高さと幅の半分だけずらします。
1 2 3 4 5 6 7 8 |
// .fooのサイズは高さ:300px、幅:300px .foo { position: absolute top: 50%; left: 50%; marging-top: -150px; margin-left: -150px; } |
「calc()」を使うと、topプロパティとleftプロパティでのみ指定できます。
1 2 3 4 5 |
.foo { position: absolute top: calc(50% - 150px); left: calc(50% - 150px); } |
Flexboxを使うと、このような方法は必要性が低くなります。ただし、Flexboxを使用できない場合(例えば、要素を絶対または固定に配置する必要がある場合)は、この方法を使用すると便利です。
「calc()」の実装例: ルートに基づいたサイズ指定
「calc()」を使用して、remユニットからビューポートベースのグリッドを作成することができます。これをするには、ルート要素のfont-sizeをビューポート幅いっぱい(100vw)を分子にして計算式を指定します。
1 2 3 |
html { font-size: calc(100vw / 30); } |
これで、1remはビューポート幅の1/30に関連づけられます。ページ上のテキストは、ビューポートに基づいて自動的にサイズが変更されます。さらに、ビューポートのサイズが同じである場合、ビューポートの実際のサイズに関係なく、同じ量のテキストが常に画面上に表示されます。
ビューポートのサイズ変更による文字のサイズの変化
remを使用してページ上に他の非テキスト要素のサイズを設定すると、この動作に従います。幅が1remの要素は、常にビューポート幅の1/30になります。
「calc()」の実装例: 計算が明白になる
最後に、「calc()」は計算をより明白にするためにも便利です。例えば、アイテムのグループ化した親コンテナの幅を1/6にしたい場合、下記のように指定するかもしれません。
1 2 3 |
.foo { width: 16.666666667%; } |
しかし下記のように指定すると、値が何を意味しているか明白です。
1 2 3 |
.foo { width: calc(100% / 6); } |
「calc()」にはCSS Grid Layoutなどで、もっといろいろな使い方ができます。それは間違いなくCSSの最も新しい機能の1つであると言えます。
参考: A Creative Grid System With Sass and calc()
sponsors