How can I set different banner images using background cover at different breakpoints?

The way I would do this would be to inline the background: url(...) property.

<?php if ( has_post_thumbnail() ) : 
    $hero = wp_get_attachment_image_src( get_post_thumbnail_id($post->ID), 'hero', '' );
    $tablet = wp_get_attachment_image_src( get_post_thumbnail_id( $post->ID), 'tablet', '' );
    $phablet = wp_get_attachment_image_src( get_post_thumbnail_id($post->ID), 'phablet', '' );
    $phone = wp_get_attachment_image_src( get_post_thumbnail_id($post->ID), 'phone', '' );
?>
<style>
    @media only screen and (min-width : 480px) {
        .banner {
            background-image: url('<?php echo $phone; ?>');
        }
    }

    @media only screen and (min-width : 768px) {
        .banner {
            background-image: url('<?php echo $phablet; ?>');
        }
    }

    @media only screen and (min-width : 992px) {
        .banner {
            background-image: url('<?php echo $tablet; ?>');
        }
    }

    @media only screen and (min-width : 1200px) {
        .banner {
            background-image: url('<?php echo $hero; ?>');
        }
    }
</style>
<?php endif; ?>

You’ll have to adjust the breakpoints to your needs. Note that I’m selecting the banner by class. If you have mutltiple banners on a page then you’ll have to assign each one an ID and use the ID to select them.

The background-size property can be in your stylesheet since it applies to all devices.


An alternative approach would be to sniff out the device on the server side and then only serve the image in the necessary size. This solution would allow you to only serve one image instead of four.

I don’t care for that solution because you have to maintain a list of user agent to device type mappings and you don’t get a whole lot of benefit.

Most browsers will not fetch images that it does not need, so even though the inline CSS solution serves up four images, only one should actually be downloaded by the browser.


The best solution, I think, would be to use the picture element. Unfortunately browser support for that element isn’t so great right now.