object-fit を使って、画像をcssで効率よくトリミングする方法

object-fit を使って、画像をcssで効率よくトリミングする方法

この記事は、htmlやcssの、比較的新しい要素をご紹介するシリーズの記事です。
今回は、画像をbox内に、css側で適切にトリミングして表示することができる
object-fit
についてご紹介します。

なお、このシリーズではこれまでに、
details と summary を使った、アコーディオン型コンテンツの作成例の記事
position: sticky; を使った、cssだけで要素を追従させる方法の記事
↑これらをご紹介してきました。併せてご覧ください。

object-fitで何ができるのか

たとえば、Webサイトを制作する案件を担当していて、カード型レイアウトを組む場所があるとします。
ここで言うカード型レイアウトとは、当サイトのTOPページに複数並んでいるような、
上に画像が入って、その下に白背景があり、そこに各投稿のタイトルが載っているようなイメージのものを想像してください。

そのカード型レイアウトの画像が入るスペースは、横320pxの縦180pxだと仮定します。
全ての画像を、その比率ぴったりに用意できる案件であれば、もちろん何の問題もありません。

ただしその部分が、
・何らかのCMSと紐づいていたりする、とか。
・投稿者が自由にアップロードする可能性があるとか。
・しかもアップロードされる画像の縦横比も、バラバラであるとか。

…こういったことが、普通にWeb制作の現場ではよくあるわけですね。

例えばそんな時に活躍してくれるのが、この object-fit です。

アスペクト比を変えずに
対象のボックスに対して
指定したサイズで良い感じに画像をフィットして配置することが可能になる」
という、優れたcssプロパティです。

コードのご紹介

上のセクションに書いたような、カード型レイアウトの上部に入る画像に、
object-fit を適用する例です。大体こんな感じで実現できます。

[html側]

<div class="card-wrapper">
  <figure class="container-image">
    <img class="item-image" src="https://picsum.photos/800/400?random=1" alt="画像の説明を記入">
  </figure>
  <div class="container-description">
    <h2>記事のタイトル</h2>
    <p>記事の説明記事の説明記事の説明...</p>
  </div>
</div>

[css側]

.card-wrapper {
  width: 320px;
}
.container-image {
  height: 180px;
  width: 100%;
}
.item-image {
  display: block;
  height: 180px;
  object-fit: cover;
  width: 100%;
}
.container-description {
  background: #fff;
  padding: 1.5rem;
}

解説など

object-fit を使用している箇所は、
imgタグに付与したclassに対して、です。
(この例では item-image という class)

上記のように、主に現場で使用されるケースでは
object-fit: cover;
が多い印象です。

ちなみに object-fit は、以下の5種類のプロパティが指定できます。

object-fit: contain;
アスペクト比を保持、親ボックスにおさまるように描画。
つまり、親ボックスと画像の比率があっていなければ、今回のようなケースでは要望を満たしません。

object-fit: cover;
今回の例で使用。親ボックスを埋めるように描画(これが重要)
親ボックスと比率があっていない場合、画像側がトリミングされます。

object-fit: fill;
アスペクト比を保持せず、親ボックスの横幅、縦幅をそのまま埋めるように画像が伸びます。

object-fit: none;
画像は拡大縮小されません。

object-fit: scale-down;
ほぼ、contain と同じ動作をします。縦横比の短い方を基準に縮小表示されます。

※ちなみに、冒頭から画像、画像と書いていますが
object-fit は img タグ以外にも、実際には video タグなどに対しても動作します。
(いまいち有効な使い方を、目にしたことはまだありませんが…)

位置調整は object-position で可能です

この object-fit ですが、上記の例のように
object-fit: cover; を使用することで、
アスペクト比が想定と違う画像が入ったとしても、
良い感じに画像の中央を中心にトリミングして配置してくれる、優れものです。

デフォルトでは、
画像の中央を中心にトリミングされますが、
少し位置をずらしたい、そんな要望もあるかもしれません。

そんな時には、object-position というプロパティを併用することで、
基準位置をずらすことが可能です。

object-fit: cover;
object-position: 0 -1rem;

↑このように指定することで、
x軸方向はデフォルトのまま
y軸方向は上から 1rem分 ずらして配置

といったことが可能です。

ちなみに、object-position のデフォルト値は
50% 50% となっており、
つまり中央、と言うことですね。

background-image を使えば良いのでは?という疑問

「サイズが決め打ちで画像が入る部分があるなら、
そこは背景画像にしてしまって、background-size でサイズを指定しておけば
何の問題もないんじゃないの?」

と思う方、いると思います。確かにそれも一理あって、選択肢の一つではあります。
ただし、Web制作の現場では
altを設定できるからSEO的に有利
pictureタグと併用することで、Webサイトの高速化が狙える
といった理由から、
「背景画像にはしないでね!ここは必ずimgタグでよろしく」
といったオーダーが来る事もよくあります。

背景画像にして問題ない案件なら、もちろん背景画像で良いのです。
画像の上にキャッチコピーを載せたい場合など、それがふさわしいケースもあります。

しかし、この記事で言いたいのは、

制作者として、引き出しは多く持っておく方が良い

と言う事です。
その方がきっと、多くの人を笑顔にできます。

現在、唯一対応していないブラウザが、IE11。これにどう対応すれば良いのか。ポリフィルのご紹介

この問題は2022年6月15日に解決します(IE11の公式サポートがその日に満了を迎える)が、
それまでの間、もし対象のサイトがIEをサポートしなければならない場合。そんな時はこちらのポリフィルを読み込ませれば、object-fitがIE11でも動作します。
object-fit-polyfill

ライセンスはこちら。
object-fit-polyfill/LICENSE.md

使い方は、上記のgitリポジトリからスクリプトをDLして、
distディレクトリ内の objectFitPolyfill.min.js を読み込ませる形です(上記のgithubページにも、#usage の部分に読み込み方・使い方が書いてあります)。

また、対象の画像の img タグには
data-object-fit="cover"
のように、data属性を指定します。

※ちなみに、そもそも「ポリフィルって何?」という場合、以下の記事が詳しいです。
Polyfill (ポリフィル) – MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN

この記事のまとめ

新しい技術が次々と生まれ、常に進化を続けているWeb制作、Webデザインの手法。

その流れの中で、新しいhtml要素や新しいcssプロパティ自体も次々と出てきています。
しかしこれらは、IE11をはじめとするブラウザの対応状況が十分でなく、
ここ数年間は、実制作の案件では採用することにハードルが高かった印象があり、実践投入は見送るケースが多い事実がありました。
(もし採用するにしても、別途、動作を補完するjsライブラリ、いわゆるポリフィルが必要だったりしました)

しかし2021年も残すところ60日ほどになった現在では、
ついに各ブラウザの対応状況も徐々に改善してきていまして、
これらの新しいhtml要素や新しいcssプロパティも、実制作での採用を検討できそうな雰囲気が整ってきました。

今回ご紹介した object-fit の他にも、
おもしろそうなプロパティや、そのサンプルを思い付いたら
また記事を書いていきたいと思ってます。

※この記事は、内容の品質向上を目的に、随時更新を行う場合があります。