「あ〜、夏も終わるな〜。リキッドレイアウトなんだけどサイドバーの幅は固定でメインコンテンツ幅だけ可変にできないかな〜。」
って思ったこと、皆さんありますよね?夏ですしね。
どうもこんにちは、制作部の崎本です。
固定要素と可変要素が組み合わさるとめんどくさい!
通常、cssのプロパティ値はpx, %, em, rem, vw, vhなど単一の単位を以って値の指定をします。
pxで絶対指定したり
.hoge { width: 100px; }
%などで相対指定したり
.hoge { width: 70%; }
色々な指定が可能なのは基本のキですよね。
基本的なレイアウトであればこれらの単位指定の使い分けでレスポンシブ対応含め実装可能かと思います。
では、冒頭のような場合はどうでしょうか?
例えば以下のようなレイアウトを想定してみましょう。
- コンテンツ全体(#container)最大幅 1000px
- 左部メインコンテンツ(#content)最大幅 750px
- 右部サイドバー(#sidebar)幅 200px固定
- メインコンテンツとサイドバーの間 50px固定
「サイドバーの幅とマージンは固定とし、メインコンテンツ部分の幅は可変で残りを埋める」ということです。
さて、この時各要素の幅指定はどうしましょうか?
細かいレイアウトは置いといて、幅についてのみ考えます。
「幅固定のサイドバーはpxで絶対指定、可変にしたいメインコンテンツは親要素幅に対して%で相対指定かな!」
#container { width: 100%; max-width: 1000px; } #content { float: left; width: 75%; } #sidebar { float: right; width: 200px; }
これでOK?
これなら幅1000px以上の画面ではしっかり想定通り表示されますね。
では画面幅を狭めて行きましょう^ ^
画面幅800pxまで狭めると、、、
#content 幅600px(800×75%)
#sidebar 幅200px
左右の間 0px
デデ〜ン!崎本、アウト〜!
左右要素がくっ付いてしまいました。
まあこんなことはすぐ気付く訳なんですが。
意外と実装しにくくないですか?
僕だけですか?
まあJSとか使ってしまえば全然実装可能なんですが、CSSだけで済んだらそれに越したことはないじゃないですか。
というわけでcalc()関数の登場です。
calc()関数とは
CSSのcalc()関数は、プロパティの値を計算式で実行することができます。
はて、これは一体どういうことか。
前述のケースで実装したいのは、
「#contentのwidthを常に幅いっぱい100%から#sidebarのwidthと間の余白の固定分を除いた値にする」
ということになります。
この計算をCSSで行うことができるのがcalc()関数になります。
先に解決例を出してしまいますね。
#cantainerと#sidebarは変わらず、#contentを以下のように記述します。
#content { float: left; width: calc(100% - 200px - 50px); }
これでOKです!
このようにcalc()関数を使用することでプロバティ値に計算式を指定することができるのです。
括弧の中はまさに「#contentのwidthを常に幅いっぱい100%から#sidebarのwidth(200px)と間の余白(50px)の固定分を除いた値にする」そのものですね。
しかも上記の通り異なる単位同士で計算することができるのです。
なんて便利!
calc()関数の使い方
calc()関数はCSS内で<length>(長さ), <frequency>(周波数), <angle>(角度), <time>(時間), <number>(数量), <integer>(整数値)を利用する場所ならばどこでも使用できます。
そして計算式内では四則演算(加算、減算、乗算、除算)が使用可能です。
例えばある要素の幅を親要素の1/3にしたい時、widthの値を33.33333%とかに指定してませんか?
calc()関数を使用すると次のように指定できます。
.item_a { width: calc(100% / 3); }
これでOK。
何を表しているか一目瞭然ですね。
除算便利。
もう一つ例を。
ある要素のフォントサイズを親要素より少し大きくしたい時は。。。
.item_b { font-size: calc(1em + 3px); }
こうすることで常に1em(親要素のフォントサイズ)+3pxの値をフォントサイズとして指定できます。
ほほ〜
使用上の注意点
ブラウザ実装状況
calc()関数はOpera Miniを除くほとんどのメジャーブラウザでサポートされており、古いバージョンのブラウザに対してもベンダープレフィックス(-webkit-)付与で使用できます。
しかし非サポートブラウザ想定の対応も必要なので、使用する時は静的な値でのフォールバックも忘れないようにしましょう。
.item_a { width: 33.33333%; /* 非サポートブラウザ用のフォールバック */ width: -webkit-calc(100% / 3); width: calc(100% / 3); } .item_b { font-size: 105%; /* 非サポートブラウザ用のフォールバック */ font-size: -webkit-calc(1em + 3px); font-size: calc(1em + 3px); }
構文
0で割らない
四則演算の基本です。
演算子(+, -, *, /)は前後にスペースが必要
特に+と-は前後スペースがない場合、それぞれ単に正の数、負の数として扱われてしまいます。
例えばcalc(100% – 200px)は減算式として成立しますが、calc(100% -200px)は100%と-200pxという二つの値が並んでいるということになり計算式として成立しなくなります。
*と/は実は前後スペースがなくても成り立つのですが、記述の統一のためにスペースを用いることが推奨されています。
入れ子可能
calc()内にcalc()を含める入れ子構造を取ることが可能です。
例えば前述の要素の幅を親要素の1/3にしたいというケースで、いややっぱり2/3にしたいとなった時は、次のような入れ子構造をとることで実装できます。
.item_1 { width: calc(100% / calc(2 / 3)); }
この場合、内部関数は単純な括弧として扱われます。
便利な使用例
すでにここまでで幾つかメジャーかつ実用的な例は出したのですが、もう二つほど紹介して終わろうと思います。
ヒーローヘッダーの高さ調整
ヒーローヘッダーってかっこいいですよね。
ファーストビューに画像どーんってやつ。
基本は縦横画面いっぱいにすれば良い訳ですが、ヘッダーメニューのせいで画像の収まりが悪いなんてこともあるかと思います。
そんな時はこうです。
// ヘッダーの高さが100pxの場合 #mv { height: calc(100vh - 100px); }
absolute上下中央配置
高さの固定されている要素を親要素の上下中央に配置したい時って結構あると思います。
個人的には擬似要素で作ったアイコンを配置したりなんかよくやります。
そんな時、よくある方法としてネガティヴマージンの使用があるかと思うんですが、それもcalc()関数でスッキリさせることが可能です。
// .hoge::beforeは高さ100px固定 .hoge::before { position: absolute; top: 50%; margin-top: -50px; }
皆さん一度は書いたことありますよね。
ちなみに配置に関する指定以外は省いています。
で、これをcalc()関数を使うと次のように書けます。
// .hoge::beforeは高さ100px固定 .hoge::before { position: absolute; top: calc(50% - 50px); }
ネガティヴマージンで調整していた分を初めから計算式に組み込む訳ですね。
まとめ
知らなくてもなんとかなるけど知ってると便利!
君のちょっとした不満を解決してくれるそんなやつ。
頭の隅に置いておくといざという時役に立つかもしれません。
ちなみにcalcは「calculation(計算)」の略です。
納得!
参考サイト
calc() – CSS: カスケーディングスタイルシート | MDN
https://developer.mozilla.org/ja/docs/Web/CSS/calc