カラーモード

TRBL メソッドで background-size を代替する

CSS

親要素に対して子要素を上下左右に中央配置する 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; のような表示が可能になる。

元ネタはそめさんのツイートから。

要件

普通に 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;
  /* 水平方向を常に100%にする */
  width: 100%;
}
/* like background-size: auto 100%; */
.wrap img {
  position: absolute;
  top: -100%;
  right: -100%;
  bottom: -100%;
  left: -100%;
  margin: auto;
  /* 垂直方向を常に100%にする */
  height: 100%;
}
/* like background-size: contain; */
.wrap img {
  position: absolute;
  top: -100%;
  right: -100%;
  bottom: -100%;
  left: -100%;
  margin: auto;
  /* 水平・垂直ともに「最大で100%」にする */
  max-width: 100%;
  max-height: 100%;
}
/* like background-size: cover; */
.wrap img {
  position: absolute;
  top: -100%;
  right: -100%;
  bottom: -100%;
  left: -100%;
  margin: auto;
  /* 水平・垂直ともに「最小で100%」にする */
  min-width: 100%;
  min-height: 100%;
}

JS でクラスを操作する関係で CSS が少し読みづらい。なのでルールセットは上記を参考にしてほしい。

TRBL: 0;ではなく TRBL: -100%;

contain を代替したい時は 4 辺の値は -100% でも 0 でもよいが、それ以外の時は -100% でないと、ブラウザによっては縦や横方向のセンタリングがうまく効いてくれない場合があった。手元で確認した限り次の通りだ。

4辺0値のTRBLメソッドでセンタリングができない方向
代替したい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(検証を手伝ってくれたので今半をおごる可能性が高い)