How can object-fit property save you from misusing the background images
Tags: css, webdev
Published: 2020-02-17 11:44:40

It's a very common situation - you have an image that needs to fit its content box without losing the aspect ratio. It seems that the easiest way to solve the problem is to insert your picture via CSS <code>background-image</code> and give it the <code>background-size: cover</code> property. There are also other <code>background-*</code> properties that can help you with positioning and styling. 

However, inserting images with CSS is not always the most appropriate choice. **It's how the purely decorative images should be handled**. When it comes to the images that are providing any kind of meaningful information, 👉 **<code>object-fit</code> gives us the ability to manipulate the content inside the \<img> tag in a very similar way as <code>background-size</code> does with CSS-inserted background images**.

**TL;DR**: Don't use <code>background-\*</code> for images, videos or other replaced elements that are providing any kind of information, concepts or functionality. 👉 **Use inline images and style them in CSS with <code>object-fit</code> and <code>object-position</code> instead**.

For the sake of brevity, I will write mostly about handling images, instead referring to each kind of replaced elements separately. The main idea is the same, though. 

## Summary

👉 [*background-*\* vs *object-fit*](#comparison)
👉 [Background images are not accessible](#accessibility)
👉 [Background images are not SEO-friendly](#seo)
👉 [Are there any performance issues with background images?](#performance)
👉 [Conclusion](#conclusion)

## Background vs object-fit <a name='comparison'></a>
  
<code>object-fit</code> is used to fit image or video ([and every other replaced element](https://developer.mozilla.org/en-US/docs/Web/CSS/Replaced_element)) to its content box. Images with **non-decorative content** should be inserted like this into the HTML document and further styled in the CSS stylesheet 👇

```html
<!--index.html-->
<img src='meaningful-image.jpg' alt='this text describes the image' 
 class='.my-html-image'/>
```
```css
/*style.css*/
.my-html-image {
 object-fit: cover;
 object-position: left 10%, top 15%;
}
```
Check the CodePen demo below for working example of <code>object-fit</code> values:
{% codepen https://codepen.io/Ekaterina_Vu/pen/poJjXqR %}

**Decorative background images** should be inserted like this into the CSS stylesheet 👇  
	
```css
/*style.css*/
.my-div {
    background-image: url(my-special-image-url.jpg);
    background-repeat: no-repeat;
    background-position: left 10% top 15%;
    background-size: cover;
}
```
As you can see, it's not the amount or the complexity of code that makes a difference between those two ways of inserting images. The thing is that using <code>background-\*</code> for non-decorative content **have some serious drawbacks**.

##Background images are not accessible <a name='accessibility'></a>

Background images are meant to be purely decorative and it would be incorrect to make them "audible". It can be tempting to simply build a pie chart with conic gradient in CSS, but by doing it you are probably excluding people who cannot see the chart.

Screen readers and other assistive technologies rely on structural markup, and therefore, it is your responsibility as the developer to ensure that your HTML is semantically correct  in describing the functional purpose of the content. Background images don't have a corresponding markup element - you set them in CSS directly - so, **they are 'invisible' to the screen readers**. 

Besides proper HTML structure, there are other important accessibility features, like *alt* attributes for images, that cannot be used with <code>background-\*</code> properties. 

<blockquote><p>Browsers do not provide any special information on background images to assistive technology. This is important primarily for screen readers, as a screen reader will not announce its presence and therefore convey nothing to its users. 👉 If the image contains information critical to understanding the page's overall purpose, it is better to describe it semantically in the document.</p>
<footer>-MDN, <cite><a href ='https://developer.mozilla.org/en-US/docs/Web/CSS/background'>https://developer.mozilla.org/en-US/docs/Web/CSS/background</a></cite></footer></blockquote>

##Background images are not SEO-friendly <a name='seo'></a>

Google parses the HTML of your pages to index images, **but doesn't index CSS images**. 👉 If you want your images to rank in Google Image search then you best use \<img> tag with the *src* attribute pointing at the image. That said, it would be a shame to hide your visual content behind the <code> background-image</code>, especcially if it's a custom content that is additionally backing up your message. 

As previously mentioned, <code>background</code> is purely CSS property and doesn't have a corresponding HTML tag or attributes. 👉 For good SEO results images should be placed near relevant text, have alt tags and maybe a caption - you can't do any of those with <code>background-*</code>.

## Are there any performance issues with background images? <a name='performance'></a>

Yes, but there is hope on the horizon. There are some significant shortcomings regarding performance of background images:  

👉 **Background images are discovered by browser only after all CSS in page's \<head> element has been downloaded and parsed**. If there is a substantial amount of CSS, it may cause slower loading of the background image.

👉 Likewise, it is impossible to **provide high-res images** without writing a bunch of device pixel ratio media queries, which is a [non-standard feature](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/-webkit-device-pixel-ratio).

**image-set()** is a new feature that allows us to use different background images for different screen densities (just like *srcset* attribute in \<img> tag) - hence solving the second problem. Even more so, image-set() can be used with the new *preload* feature 👇

<blockquote><p>The preload value of the &lt;link&gt; element's rel attribute lets you declare fetch requests in the HTML's &lt;head&gt;, specifying resources that your page will need very soon, which you want to start loading early in the page lifecycle, before browsers' main rendering machinery kicks in. 👉 This ensures they are available earlier and are less likely to block the page's render, improving performance.</p>
<footer>- MDN, <cite><a href='https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content'>https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content</a></cite></footer></blockquote>

So, hopefully, if the browser support ever gets just a bit better for both [image-set()](https://caniuse.com/#search=image-set()) and [preload](https://caniuse.com/#search=preload), we can consider both issues solved. 

For more information, read this [article on Google Developers](https://web.dev/preload-responsive-images/#preloading-background-images-using-image-set).

## Conclusion <a name='conclusion'></a>

Background images are not "bad" per se, they just have some shortcomings when implemented in the incorrect way. You should definitely choose them for abstract background pattern, background color / gradient, or some blurry, decorative image. But for your hero image or any other meaningful content, you might consider the \<img> and \<picture> tags, together with <code>object-fit</code> and <code>object-position</code>. The latter provides much more opportunities for accessible, easily discoverable and performant images.