こんにちは。
サイトを作ってる時、デザインによっては、%指定とピクセル指定を混在させたい時ってありませんか?
例えば、「幅100%指定しつつそのなかの要素はそこから10px引いたサイズを利用したい」なんて状況ですね。
そんな時は calc() というファンクションを使うと簡単に実現できるそうです。
どんな時に使うのか
例えば hx タグの装飾でたまに見かけるこーんなデザイン
普通に書くとこんな感じでしょうか?
1 2 3 4 5 6 7 8 9 10 11 12 13 |
h1 { font-size: 16px; border: 1px solid #cccccc; background-color: #2f3297; position: relative; padding: 6px; color: #ffffff; } h1 .inner { border-left: 2px solid #f11d25; background-color: #2f3297; padding: 5px 5px 5px 10px; } |
ですがこれだと h1 の中に更に .inner 要素を作る必要があります。この後出てくるもう1つの方法に見られる問題も発生しません。
しかしこれだとCMSとかオーサリングソフトを使ってビジュアルモードで更新を行うクライアントさんにはちょっと使いにくいですよね。
「あたしゃーえいちてーえむえるなんてわかんないのよ!!もっとこう、ボタン1つでバーン!って感じにならないの?」
となるのは目に見えてます。
そこで次に思いつくのが擬似要素を使用する方法です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
h1 { background-color: #2F3297; color: #fcfcfc; padding-left: 15px; min-height: 45px; line-height: 45px; position: relative; margin-bottom: 10px; } h1:before { content: ''; width: 2px; height:35px; background-color: #F11D25; position: absolute; margin: 5px; top: 0; left: 0; } |
これなら h1 タグの中に要素を追加する必要もなく一見問題なさそうに見えます。
ですがこれにも問題が有ります。つまりながーいタイトルが来た時にこれだとカバーしきれなくなって、こうなります。
うーん、惜しい。
個人的にはこれはこれでアリな気もしますが、多分お客さん的には「この赤線はなんで伸びないのかね?ちみはこんな中途半端に伸びた赤線がナウでイケイケなデザインだと本気で思ってるのかい?ええ?」となるわけです。
なんでこうなったのかというと、コードを見ればわかりますが、擬似要素の高さが35px固定だからですね。
それならここも100%にすれば良さそうですが、でもそうると残念なことに、「赤線が飛び出す」現象が発生します。これは赤線を少し中にいれるのに margin 指定をおこなっているせいです。
指定方法が悪いのか、そもそも対応していないのかは判りませんが、 box-sizing でもうまくいきませんでした。。
と、いうことでようやく登場しますのがこの calc() ファンクションでございます。
calc()とはなんぞや?
calcとは calculate つまり、計算ですね。一言で言うならば、
要素の大きさを指定する際に計算式が利用できる
というものです。
つまり、「基本的には100%なんだけど、そこから更に10px分ほど短い流しにして頂戴」みたいな無理難題に応えることができるのです。
使い方は簡単で、上の例なら、
1 2 3 |
.foo { width:calc(100% - 10px); } |
と書くだけです。が、後で書きますがブラウザの対応状況を見ると、まだ-webkit-は付けておいたほうが良いようです。あと、Androidが現状NGなのでまだガッツリとスマホサイトでは使うには早いのかも…。
サポートしているブラウザとバージョン
で。問題の対応ブラウザですが、
IE | IE9〜 |
Chrome | Chrome26〜 (Chrome19から25までは -webkit- をつける) |
Firefox | Firefox16〜 (Firefox4から15までは -moz- をつける) |
Safari | Safari6.1,Safari7.0〜 (Safari6.0は -webkit- をつける) |
Opera | Opera15〜 |
iOS | iOS7〜 (iOS6.xは -webkit- をつける) |
Android | 未対応 |
なんということでしょう。まさかのAndroidのみ未対応でした。
スマホブラウザは比較的CSS3をがっつり使ってもOKな環境だと思っていたのですが、これに関してはちょっと注意が必要そうですね。
ただ、Can I use calc() as CSS unit valueを見た感じですと、近いうちに対応しそうなので、じきに使えるようになるとは思いますが。スマホは買い替えのサイクルがPCより早いので多分あと数年もすれば意識せずに使ってOKになるんじゃないかな…と期待したいところです。
ということで実際にはこんな風にすると良いようです
1 2 3 4 5 |
.foo { height:98%; height:-webkit-calc(100% - 20px); height:calc(100% - 20px); } |
ちなみに最初の width 98% は対応していない古いIEとAndroidをフォローするため近い見た目になるような値を指定しています。この方法だと親の長さによって実際の長さが若干変化してしまいますが、まぁ仕方ないですよね。
因みに長さだけじゃなく、
- margin
- font-size
- background-position
- text-shadow
- transform:rotate()
など、かなり色んな所に適用できるみたいです。
計算には所謂四則演算が利用できますが、一部条件があったりもするみたいです。
では早速試してみます。
下のインプットフィールドに適当に文字を入れると、上のh1要素のテキストが入れ替わるようにしましたので、適当にテキストを入力してみて、要素の中でテキストが折り返すようになっても赤線がちゃんと伸びているのがわかると思います。
サポートしているブラウザとバージョン
先程も書いたように、AndroidだけNGでした。
スマホブラウザは比較的CSS3をがっつり使ってもOKな環境だと思っていたのですが、これに関してはちょっと注意が必要そうですね。
ただ、Can I use calc() as CSS unit valueを見た感じですと、近いうちに対応しそうなので、じきに使えるようになるとは思いますが。スマホは買い替えのサイクルがPCより早いので多分あと数年もすれば意識せずに使ってOKになるんじゃないかな…と期待したいところです。
追記
嫁さんからツッコミを受けたので誤植を修正しました。あと、calcを使わないで何とかする方法も教えてくれたんでそちらも紹介しておきます。
clac使わないで似たようなことをやってみるテスト – jsdo.it – Share JavaScript, HTML5 and CSS
更に追記
なんかSASSでそのまま calc (100% – 20px) とか書くとバリデーションエラーになるんで、
1 2 3 4 |
.foo { $negative_pixel :50px; height: calc (100% - #{$negative_pixel}); } |
みたいな感じにしないとダメみたいです。
SASS Variable in CSS calc() function – Stack Overflow
[…] ちなみに旦那さんはpaddingを指定したhタグのbeforeをボーダー状にするとき、高さを100%で指定するとはみ出るのでその対策に使っていました。予想外の使い方・・・ 最近CSS3を勉強してい […]
[…] [参照] CSS の calc を使えば複雑なサイズ指定が可能らしい ここに色々載っています。 […]