置換要素のレイアウトのためのプロパティ object-fitとobject-position

置換要素のレイアウトを簡便にできる2つのCSSプロパティ、object-fitとobject-positionを紹介します。手元で試して感覚をつかんでみてください(仕様はまだ不安定なので、今後変わる可能性があります)。IEとEdgeが対応していないため、まだ現場ではすんなり使うことができませんが、置換要素のレイアウトを簡便にできる2つのCSSプロパティを紹介します。手元で試して感覚をつかんでみてください。

発行

著者 坂巻 翔大郎 フロントエンド・エンジニア
置換要素のレイアウトのためのプロパティ シリーズの記事一覧

はじめに

実務のなかで、幅や高さが同じ要素の中に、縦横比の異なる画像を「いい感じ」に表示したいと思ったことはありませんか? 筆者は、たとえば次の図のような、画像の縦横比を維持しつつ、所定の枠に収めるレイアウトを望まれることが多くあります。

しかし、img要素のみでは、このように縦横比を維持したまま「いい感じに」画像を表示することは難しく、さまざまな方法を駆使して、このレイアウトを再現してきました。しかし、今回解説するobject-fitobject-positionプロパティを使えば、今まで書いていた比較的長めな記述は不要になるかもしれません。

このobject-fitobject-positionプロパティは、CSS Image Values and Replaced Content Module Level 3(執筆現在:2012年4月17日付勧告候補)で定義されています。

これら2つのプロパティは、置換要素の内容がどのように収められるかを指定するためのものです。置換要素というのは、画像や埋め込みリソース、アプレットなどを指し、わかりやすいものでいうとimg要素・video要素・object要素・svg要素などが該当します。また、input要素のtype属性値がimageのものや、contentプロパティによって挿入されるものも置換要素となります。

本記事では、これらの対応状況や実装例を解説していきます。

なお、紹介するサンプルは次のリポジトリからダウンロード、またはクローンできます。併せて参照してください。

一歩先行くCSS:object-fitとobject-positionサンプルリポジトリ

codegrid / 2016-css-object

object-fitプロパティ

object-fitプロパティは、置換要素の内容(コンテンツ)が、どのように収まるかを指定できます。背景画像の大きさを指定するbackground-sizeプロパティに似ていると考えるとわかりやすいでしょう。

object-fitプロパティには、執筆時点(2016年10月2日)では、IE、Edge*以外が対応しています。

*注:Edgeの対応

MicrosoftのDeveloper Feedbackの2016年10月6日付コメントによれば、object-fitobject-positionの実装が、高いプライオリティ(もうすぐ開発を開始する)でバックログに追加されたとのことです。

期待される状態
fill 初期値。コンテンツは、その要素全体を埋めるサイズになる。その結果、縦横比が保たれない場合がある
contain コンテンツは、その要素内に合うサイズになり、縦横比は維持される。コンテンツは歪まず、その要素内に収まる
cover コンテンツが、元々の縦横比を保ちながら、その要素内を完全に覆うように変形する。コンテンツの持つ幅と高さの短いものが要素にフィットし、長いものはその要素からはみ出る
none コンテンツは、その要素の幅や高さを無視する
scale-down コンテンツは、noneまたはcontainを指定したかのようになり、表示したいコンテンツがその要素よりも小さければnoneが適用される

それぞれの値を比較できるデモを用意しました。

object-fitプロパティの値によって、img要素に表示されるコンテンツが変形していることが確認できます。

上記のデモではobject-fit: scale-down;の動作がわかりづらいため、noneまたはcontainが適用されることを確認できるデモも用意しました。

左右の画像どちらも、object-fit: scale-down;を指定しています。画像自体の大きさは、幅200px、高さ150pxです。

左側は、画像自身がimg要素のサイズよりも大きいため、object-fit: contain;として扱われます。この場合、画像は縦横比を維持して縮小され、その要素内に収まっています。一方、右側は、画像自身がimg要素のサイズよりも小さいため、object-fit: none;として扱われ、変形せずimg要素の中心に表示されています。

基本的には、object-fitプロパティの値によって表示される画像の位置は、その要素の中央になります。この位置を調整したい場合は、object-positionプロパティを使用します。

object-positionプロパティ

object-positionプロパティは、置換要素の内容をどこに位置させるかを指定します。背景画像の位置を指定するbackground-positionプロパティに似ていると考えるとわかりやすいでしょう。

object-positionプロパティには、執筆時点(2016年10月2日)では、IE、Edge以外が対応しています。Safari 9まではobject-fitプロパティのみで、object-positionプロパティには対応していませんでしたが、2016年9月末に、Safari 10になった際に、object-positionプロパティに対応しました。

初期値はobject-position: 50% 50%;であるため、先ほどのデモでは、その要素の中央にコンテンツが表示されます。background-positionプロパティの指定と同様に、%pxで指定することもできます。

また、background-positionプロパティと同様ですが、アニメーションすることもできます。次のデモはobject-positionプロパティをアニメーションしています。

HTMLは、img要素を配置し、画像を表示するだけです。

img要素

<div class="visual">
  <img class="visual__image" src="../asset/img_02.jpg" alt=" ">
</div>

CSSではimg.visual__imageに、object-fit: none;を指定し、img要素のサイズを無視して、画像を変形させずに表示し、object-positionプロパティの値を変化させ、アニメーションしています。

CSSの指定

.visual {
  width: 500px;
  height: 500px;
}
.visual__image {
  width: 100%;
  height: 100%;
  object-fit: none;
  object-position: 0% 0%;
  animation: slide 50s normal infinite;
}
@keyframes slide {
  0%   { object-position:   0%   0%; }
  25%  { object-position: 100%   0%; }
  50%  { object-position: 100% 100%; }
  75%  { object-position:   0% 100%; }
  100% { object-position:   0%   0%; }
}

このアニメーションの実務での利用シーンは……? となると筆者はあまり思いつきませんが、こうしたこともできるということを頭の片隅にいれておいても良いでしょう。

object-fitやobject-positionを使用したサンプル

最後に、object-fitobject-positionを使用したサンプルをいくつか紹介します。

サムネイルリスト

冒頭で登場した、幅や高さが同じ要素の中に、縦横比の異なる画像を比率を保ったまま「いい感じ」に表示するような、サムネイルリストです。まずはデモから確認します。

このデモのHTMLは、次のようになっています。サムネイルを表示したimg要素にa要素で元画像へのリンクを張っています。

サムネイルリストのHTML

<div class="thumbList">
  <a class="thumbList__link" href="../asset/img_03.jpg"><img class="thumbList__item" src="../asset/img_03.jpg" alt=" "></a>
  <a class="thumbList__link" href="../asset/img_04.jpg"><img class="thumbList__item" src="../asset/img_04.jpg" alt=" "></a>
  <!-- 省略 -->
  <a class="thumbList__link" href="../asset/img_08.jpg"><img class="thumbList__item" src="../asset/img_08.jpg" alt=" "></a>
</div>

CSSは、要素を横に並べるためにFlexboxを使用していますが、img要素の幅と高さを180pxにし、object-fit: contain;としているため、そこに表示される画像は自体の縦横比を維持し、その要素内に収まり、中央に表示されます。

サムネイルリストのCSS

.thumbList {
  width: 570px;
  display: flex;
  flex-wrap: wrap;
  padding: 5px;
}
.thumbList__link {
  display: block;
  flex: 0 0 auto;
  width: 180px;
  height: 180px;
  margin: 5px;
}
.thumbList__item {
  box-sizing: border-box;
  object-fit: contain;
  width: 100%;
  height: 100%;
  padding: 5px;
  border: 1px solid #ccc;
  background-color: #fff;
  transition: 0.2s all linear;
}
.thumbList__link:hover .thumbList__item {
  border-color: #2185da;
  background-color: #ace2ee;
}

このサムネイルリストを、object-fitプロパティを使わずに実装しようとすると、object-fit: contain;だけで済む部分には、もっと多くの指定が必要になるでしょう。

動画の字幕を表示する領域を作る

次のサンプルを見てみましょう。たとえば、動画の字幕をtrack要素*を使い、動画上に出す場合に、その字幕が表示される領域を確保するために使えるかもしれません。まずはデモを見てみましょう(Chromeを推奨します)。

*注:track要素

video要素とともに使用されることが多く、主に動画に字幕やキャプションをつけるために使われる要素です。

HTMLではvideo要素内で、source要素を使用し読み込む動画を指定します(この動画の実サイズは幅250px・高さ140px)。そして字幕用のWebVTTというデータフォーマットに沿って作成したVTTファイルをtrack要素で読み込むように指定します。

動画字幕を表示するサンプルのHTML

<video class="with-caption" autoplay controls muted>
  <source src="https://s3-ap-northeast-1.amazonaws.com/codegrid/webgl/demo/canvas/movie.webm" type="video/webm">
  <source src="https://s3-ap-northeast-1.amazonaws.com/codegrid/webgl/demo/canvas/movie.mp4" type="video/mp4">
  <track label="Japanese" kind="captions" srclang="ja" src="../asset/sample-movie-ja.vtt" type="text/vtt" default>
</video>

次にCSSの部分を見ていきます。

動画字幕を表示するサンプルのCSS

.with-caption {
  object-fit: contain;
  object-position: top center;
  background-color: #000;
  width: 500px;
  height: 370px;
  border: 10px solid #aaa;
}

object-fit: contain;としているので、動画は縦横比を維持します。さらにobject-position: top center;としているので、上部の中心に位置します。下に90pxの余白が生まれ背景の黒が見えています。そして、動画が再生されれば、その位置に字幕が表示されます。字幕の位置に関しては、VTTファイルの中で上部から90%の位置になるように指定しています。

こういった使い方が正しいとはいえませんが、この字幕のデモのように、余白の部分をうまく活用できるようになるということがわかるかと思います。

まとめ

object-fitobject-positionプロパティが利用できるようになることで、画像が動画の縦横比を維持しつつ、その要素内にフィットさせることが可能になります。デモにもあったように、実務の中で、縦横比を維持したサムネイルリストは頻繁に登場するので、もし案件が対象とするブラウザに、これらのプロパティに対応しないブラウザ(IEやEdge)が含まれないのであれば、積極的に利用していってよいのではないかと筆者は思います。

筆者の場合は、ある矩形の中に、比率を維持した画像を上下中央で配置するといったことをするケースが多いのですが、画像や動画を要素の全面に敷く際にも有用なのではないでしょうか。

執筆現在、Edgeも対応を開始しようとしているという情報もあります。今すぐには利用できない状況であっても、どういうことができるのかだけでも覚えていただければ幸いです。