Search code examples
htmlcsssrcsetimageset

How to provide adaptive full-width images with CSS background-image — or otherwise?


My site has full-width hero images. There are currently served as a CSS background-image with a single image URL that is 2000px wide. Loading one or more of these images on a small device is definitely sub-optimal. I would like to serve a 2000px image, a 1440px image, a 992px image, etc to improve page loading time on mobile.

It seems that I can use -webkit-image-set and image-set, but these only take dpi and 1x, 2x, etc. sizes, so that won't help in this case, as I understand it because this won't ever show smaller images on smaller screens. Alternately, I could serve different images with a media query, but that gets complicated fast if you want to serve images based on viewport and if a device is 2x or 3x. Or I could switch to a img tag instead and use srcset, but I have not been able to find a solution to get a full width image that scales both up and down and fills a fixed height. It seems like this should be possible with object-fit: cover, but no combination of max-width, height, max-height, etc that I have tried has worked.

Here's an example of the CSS background-image that I'm trying to make adaptive:

.hero {
display: block;
min-height: 80px;
width: 100%;
float: left;
position: relative;
padding: 0;
-webkit-background-size: cover;
background-size: cover;
background-position: center center;
background-image: url("https://place-hold.it/500x100");
}
<div style="width: 500px;"> <!-- for this example, is 100% on our page -->
<a class="hero"></a>
</div>

This is on Wordpress with Boostrap.


Solution

  • Here is how you can do that with a picture tag. I like using this tag because i think it gives you more control over the breakpoints.

    Look it up here: https://www.w3schools.com/tags/tag_picture.asp

    /* Basic styling for body. not important */
    
    body,
    html {
      margin: 0;
      padding: 0;
      width: 100%;
      height: 100%;
    }
    
    
    /* The parent container needs to have position:relative */
    
    .example-container {
      position: relative;
      width: 100%;
      height: 100%;
      overflow: hidden;
      display: flex;
      justify-content: center;
      align-items: center;
      text-align: center;
      color: #fff;
    }
    
    
    /* The content element needs position:relative, and z-index higher than the BG element */
    
    .example-content {
      position: relative;
      z-index: 10;
      margin: 0;
    }
    
    
    /* The picture element */
    
    .image-full,
    .image-full img {
      display: block;
      
      /* Absolute position the element with full width/height, and a low z-index */
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      z-index: 1;
      
      /* Object-fit:cover will make the image fill the space */
      object-fit: cover;
      object-position: center;
    }
    <div class="example-container">
      <h2 class="example-content">Content goes here</h2>
      <picture class="image-full">
        <source media="(min-width:1200px)" srcset="https://i.picsum.photos/id/1002/4312/2868.jpg?hmac=5LlLE-NY9oMnmIQp7ms6IfdvSUQOzP_O3DPMWmyNxwo">
        <source media="(min-width:500px)" srcset="https://i.picsum.photos/id/10/2500/1667.jpg?hmac=J04WWC_ebchx3WwzbM-Z4_KC_LeLBWr5LZMaAkWkF68">
        <img src="https://i.picsum.photos/id/100/2500/1656.jpg?hmac=gWyN-7ZB32rkAjMhKXQgdHOIBRHyTSgzuOK6U0vXb1w">
      </picture>
    </div>