TRBLメソッドでbackground-sizeを代替する
親要素に対して子要素を上下左右に中央配置するTRBLメソッドというものがある。
.wrap{
position: relative;
width: 300px;
height: 300px;
border: 1px solid magenta;
resize: both;
overflow: hidden;
}
.inner{
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
width: 176px;
height: 244px;
background-color: grey;
}
.innerをimgタグにして、画像の大きさが不定の時でも頑張る方法は以前記事にしているので参考までに。
このTRBLメソッドでさらに頑張ると、背景指定ではなくimgタグを使いつつもbackground-size: 100% auto;
のような表示が可能になる。
元ネタはそめさんのツイートから。
要件
- div > imgの構造
- divの幅と高さは固定
- imgの大きさは不定
- imgはdivに対して横幅いっぱいに表示させたい
- divに対してimgの高さが大きい時は上下に均等にはみ出させて隠す
- divに対してimgの高さが小さい時は上下に均等に余白を残す
- IE8でも表示できる
普通にimg{width: 100%;}
するだけだと上下方向のセンタリングができない。背景画像を指定する方法で幅のフィットだけ(クライアントに)諦めさせたいところだけど、構造が変えられないので不可。background-sizeでやれれば一番簡単だけどIE8はbackground-sizeプロパティに対応していない。ということでTRBLメソッドを使う。
画像の横幅が常に親要素にフィットするということはwidth: 100%;
を加えるとできるが、それだけではダメで4辺の値を工夫する必要がある。
.wrap{
position: relative;
width: 300px;
height: 300px;
overflow: hidden;
}
.wrap img{
position: absolute;
top: -100%;
right: -100%;
bottom: -100%;
left: -100%;
margin: auto;
width: 100%;
}
どのサイズの画像でもbackground-size: 100% auto;
と同じ表示形式になっているのが確認できると思う。画像の読み込みが少し重い。JavaScriptがイーカゲンなのには目をつぶって欲しい。PlaceKittenはサイズの組み合わせによっては表示してくれない場合があり、珍妙なif文を書かざるを得なかった。
containもcoverも
background-sizeの他の値もTRBLメソッドの応用で代替できる。代表的な値は100% auto
, auto 100%
, contain
, cover
だろう。.wrapのルールセットは同じなので、画像のスタイルだけそれぞれまとめると下記のようになる。
/* like background-size: 100% auto; */
.wrap img{
position: absolute;
top: -100%;
right: -100%;
bottom: -100%;
left: -100%;
margin: auto;
width: 100%;
}
/* like background-size: auto 100%; */
.wrap img{
position: absolute;
top: -100%;
right: -100%;
bottom: -100%;
left: -100%;
margin: auto;
height: 100%;
}
/* like background-size: contain; */
.wrap img{
position: absolute;
top: -100%;
right: -100%;
bottom: -100%;
left: -100%;
margin: auto;
max-width: 100%;
max-height: 100%;
}
/* like background-size: cover; */
.wrap img{
position: absolute;
top: -100%;
right: -100%;
bottom: -100%;
left: -100%;
margin: auto;
min-width: 100%;
min-height: 100%;
}
JSでクラスを操作する関係でCSSが少し読みづらい。なのでルールセットは上記を参考にしてほしい。
TRBL: 0;ではなくTRBL: -100%;
containを代替したい時は4辺の値は-100%
でも0
でよいが、それ以外の時は-100%
でないと、ブラウザによっては縦や横方向のセンタリングがうまく効いてくれない場合があった。4辺0値の時の表示でこちらで確認できた組み合わせは以下のとおり。
代替したいbackground-size値 | Internet Explorer 8 | Firefox 36 | Chrome 41 |
---|---|---|---|
100% auto | - | 縦 | - |
auto 100% | 横 | 横 | 横 |
contain | - | - | - |
cover | 横 | 横と縦 | 横 |
チェックはこのページを使った。すこしややこしいのだが、上表の方向はそのまま子要素の画像が縦長か横長かとイコールになっている。つまり、「4辺0値のTRBLメソッドで100% auto
を表現しようとすると縦長の画像で縦方向のセンタリングがFirefox 36で効かない」。横長の画像なら縦方向のセンタリングはFirefox 36でもちゃんと効く、ということ。
cover
についてはFirefox 36だけは画像のアスペクト比にかかわらず両方向でセンタリングが効かず、top: 0
, left: 0
だけ指定されたような配置になる。辺指定なしのデフォルトとも見える。
互いに引っ張り合う座標指定
フィットさせて親要素より上下や左右がはみ出る画像だと、0
値ではセンタリングがうまくいかなくなるのは不思議だ。上と左へのマイナス方向の配置が不足している感じがする。-100%
値だと、4辺がお互いを大きく引っ張り合うように座標が指定され、上下も左右もセンタリングしてくれるようになるのということなのだろうか。
値は4つとも同じであれば-200%
でも-1000%
でもいいが、子要素の画像の幅や高さは親要素ベースで%計算されているので、-50%
より大きな数値にしてしまうと画像サイズによってはズレが生じてくる気がする。-100%
にしておくのが無難だと思う。
2015年になってもTRBLメソッドについて書いた。2012年にまとりさんが記事にしてからだいたい年に1回はネタにしてる。このルールセットには仕事でもずいぶん助けられたし、CSSの面白さも感じられるいいメソッドだと思う。
Special Thanks! @understandard(検証を手伝ってくれたので今半をおごる可能性が高い)