3

A Deep Dive Into object-fit And background-size In CSS

 2 years ago
source link: https://www.smashingmagazine.com/2021/10/object-fit-background-size-css/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

A Deep Dive Into object-fit And background-size In CSS

Quick summary ↬ In this article, we will go through how object-fit and background-size work, when we can use them, and why, along with some practical use cases and recommendations. Let’s dive in.

We’re not always able to load different-sized images for an HTML element. If we use a width and height that isn’t proportional to the image’s aspect ratio, the image might either be compressed or stretched. That isn’t good, and it can be solved either with object-fit for an img element or by using background-size.

First, let’s define the problem. Consider the following figure:

A good-looking photo and a squeezed image in comparison

A good-looking photo that gets squeezed when used in a card component. (Large preview)

Why is this happening?

An image will have an aspect ratio, and the browser will fill the containing box with that image. If the image’s aspect ratio is different than the width and height specified for it, then the result will be either a squeezed or stretched image.

We see this in the following figure:

A good-looking photo and a stretched image in comparison

The image’s aspect ratio is different than the containing box, and the image gets stretched. (Large preview)

The Solution #

We don’t always need to add a different-sized image when the aspect ratio of the image doesn’t align with the containing element’s width and height. Before diving into CSS solutions, I want to show you how we used to do this in photo-editing apps:

Example of an image with top and bottom edges cropped in a mask

First, we would center the image vertically, and then clip in a mask. This retains the image’s aspect ratio and prevents it from being squeezed. (Large preview)

Now that we understand how that works, let’s get into how this works in the browser. (Spoiler alert: It’s easier!)

CSS object-fit #

The object-fit property defines how the content of a replaced element such as img or video should be resized to fit its container. The default value for object-fit is fill, which can result in an image being squeezed or stretched.

Let’s go over the possible values.

More after jump! Continue reading below ↓

Meet Smashing Online Workshops on front-end & UX, with practical takeaways, live sessions, video recordings and a friendly Q&A. On design systems, CSS/JS and UX. With Carie Fisher, Stefan Baumgartner and so many others.

Jump to online workshops ↬

Possible Values for object-fit #

object-fit: contain #

In this case, the image will be resized to fit the aspect ratio of its container. If the image’s aspect ratio doesn’t match the container’s, it will be letterboxed.

object-fit: contain

When using object-fit: contain, the image will be either letterboxed or resized accordingly. (Large preview)

object-fit: cover #

Here, the image will also be resized to fit the aspect ratio of its container, and if the image’s aspect ratio doesn’t match the container’s, then it will be clipped to fit.

object-fit: cover

When using object-fit: cover, the image will be either clipped to fit or resized accordingly. (Large preview)

object-fit: fill #

With this, the image will be resized to fit the aspect ratio of its container, and if the image’s aspect ratio doesn’t match the container’s, it will be either squeezed or stretched. We don’t want that.

object-fit: fill

When using object-fit: fill, the image will be squeezed, stretched, or resized accordingly. (Large preview)

object-fit: none #

In this case, the image won’t be resized at all, neither stretched nor squeezed. It works like the cover value, but it doesn’t respect its container’s aspect ratio.

object-fit: none

When using object-fit: none, the image won’t be resized if the its dimensions are not the same. (Large preview)

Aside from object-fit, we also have the object-position property, which is responsible for positioning an image within its container.

Possible Values For object-position #

The object-position property works similar to CSS’ background-position property:

object-position center, left, right

Most of the time, the default value is used (i.e. `center` or `50% 50%`). (Large preview)

The top and bottom keywords also work when the aspect ratio of the containing box is vertically larger:

object-position top and bottom

Comparing object-position: top (left) and object-position: bottom (right). (Large preview)

CSS background-size #

With background-size, the first difference is that we’re dealing with the background, not an HTML (img) element.

Possible Values for background-size #

The possible values for background-size are auto, contain, and cover.

background-size: auto #

With auto, the image will stay at its default size:

Keep in mind that the default size may sometimes result in a blurry image (if it’s too small). (Large preview)

background-size: cover #

Here, the image will be resized to fit in the container. If the aspect ratios are not the same, then the image will be masked to fit.

When using background-size: cover, make sure to consider the aspect ratios of an image. (Large preview)

background-size: contain #

In this case, the image will be resized to fit in the container. If the aspect ratios are off, then the image will be letterboxed as shown in the next example:

background-size: contain resizes the image to fit in the container. (Large preview)

As for background-position, it’s similar to how object-position works. The only difference is that the default position of object-position is different than that of background-position.

When Not to Use object-fit or background-size #

If the element or the image is given a fixed height and has either background-size: cover or object-fit: cover applied to it, there will be a point where the image will be too wide, thus losing important detail that might affect how the user perceives the image.

Consider the following example in which the image is given a fixed height:

.card__thumb {
    height: 220px;
}

The image shown on the right is too wide because it has a fixed height while the card’s container is too wide. (Large preview)

If the card’s container is too wide, it will result in what we see on the right (an image that is too wide). That is because we are not specifying an aspect ratio.

There is only one of two fixes for this. The first is to use the padding hack to create an intrinsic ratio.

.card__thumb {
    position: relative;
    padding-bottom: 75%;
    height: 0;
}

.card__thumb img {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

The second fix is to use the new aspect-ratio CSS property. Using it, we can do the following:

.card__thumb img {
    aspect-ratio: 4 / 3;
}

Note: I’ve already written about the aspect-ratio property in detail in case you want to learn about it: “Let’s Learn About Aspect Ratio In CSS”.

Use Cases And Examples #

User Avatars #

A perfect use case for object-fit: cover is user avatars. The aspect ratio allowed for an avatar is often square. Placing an image in a square container could distort the image.

A comparison of a user avatar without object-fit and with object-fit: cover. (Large preview)

.c-avatar {
    object-fit: cover;
}

Logos List #

Listing the clients of a business is important. We will often use logos for this purpose. Because the logos will have different sizes, we need a way to resize them without distorting them.

Thankfully, object-fit: contain is a good solution for that.

.logo__img {
    width: 150px;
    height: 80px;
    object-fit: contain;
}

Using object-fit: contain can help us resize clients’ logos without distorting them. (Large preview)

Article Thumbnail #

This is a very common use case. The container for an article thumbnail might not always have an image with the same aspect ratio. This issue should be fixed by the content management system (CMS) in the first place, but it isn’t always.

.article__thumb {
    object-fit: cover;
}

Adjusting article thumbnails with a bit of help from object-fit: cover. (Large preview)

Hero Background #

In this use case, the decision of whether to use an img element or a CSS background will depend on the following:

  • Is the image important? If CSS is disabled for some reason, would we want the user to see the image?
  • Or is the image’s purpose merely decorative?

Based on our answer, we can decide which feature to use. If the image is important:

Let’s suppose that the image is important, because it’s a food-related website. 😉 (Large preview)

<section class="hero">
    <img class="hero__thumb" src="thumb.jpg" alt="" />
</section>
.hero {
    position: relative;
}

.hero__thumb {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;    
}

If the image is decorative, we can go with background-image:

.hero {
    position: relative;
    background-image: linear-gradient(to top, #a34242, rgba(0,0,0,0), url("thumb.jpg");
    background-repeat: no-repeat;
    background-size: cover;
}

The CSS is shorter in this case. Make sure that any text placed over the image is readable and accessible.

Adding a Background to an Image With object-fit: contain #

Did you know that you can add a background color to img? We would benefit from that when also using object-fit: contain.

In the example below, we have a grid of images. When the aspect ratios of the image and the container are different, the background color will appear.

img {
    object-fit: contain;
    background-color: #def4fd;
}
Adding a background color to an image with object-fit: contain

We can use object-fit: contain to add a background color to an image. (Large preview)

Video Element #

Have you ever needed a video as a background? If so, then you probably wanted it to take up the full width and height of its parent.

.hero {
    position: relative;
    background-color: #def4fd;
}

.hero__video {
    position: aboslute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
}
A figure where the video doesn’t cover the hero background

The default object-fit value for the video element is contain. As you can see here, the video doesn’t cover the hero background, even though it has position: absolute, width: 100%, and height: 100%. (Large preview)

To make it fully cover the width and height of its parent, we need to override the default object-fit value:

.hero__video {
    /* other styles */
    object-fit: cover;
}
A figure where the video covers the full width and height of its parent.

Now the video covers the full width and height of its parent. (Large preview)

Conclusion #

As we’ve seen, both object-fit and background-size are very useful for handling different image aspect ratios. We won’t always have control over setting the perfect dimensions for each image, and that’s where these two CSS features shine.

A friendly reminder on the accessibility implications of choosing between an img element and a CSS background: If the image is purely decorative, then go for a CSS background. Otherwise, an img is more suitable.

I hope you’ve found this article useful. Thank you for reading.

Smashing Editorial (vf, yk, il, al)

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK