Object Fit Workaround for Gatsby Image Plugin

17/06/18

So I have been using Gatsby more and more and I came across a bug on my portfolio page.

I had used the Gatsby-Image plugin to handle my images, and had used 'object-fit' to create a background image like feel on images, which allowed me to use all the features that Gatsby-Image offers me (Such as webp, lazy-loading and Traced SVG placeholders). But when checking my page on IE, I remembered that object-fit is not supported. This was leaving my images getting squashed.

alt text

I did not want to sacrifice my use of the Gatsby-Image plugin across all browsers for the sake of Internet explorer so I began searching the internet for a potential workaround for this.

I stumbled on this article on https://medium.com/ and it outlined how to do roughly what I wanted to do in '10 lines of JS and 10 lines of CSS'. The example was using JQuery so it required a bit of playing around to change it to vanilla JS and I also wanted to configure it to work with the gatsby-image plugin.

First I had to implement Modernizr and set it up to detect object fit support. There maybe better ways to do this, but I placed the modernizr custom build code in the gatsby-browser.js file and run it onClientEntry. This adds my objectfit/no-objectfit class onto the root element on my page.

Next, still in the gatsby-browser.js file, I detect if the browser does not support object-fit. I then grab all instances of the 'gatsby-image-wrapper' class. This is the parent of the image that the gatsby-image plugin creates. This opened up another slight problem because within this element, there are two image elements. One which is the actual image and one that is the traced SVG which is the placeholder for lazy loading. I needed the src of the actual image. I noticed the image I was after had an attribute of 'sizes', so I put in some logic to ensure I was getting that image.

if ( ! Modernizr.objectfit ) {
        const allImageContainers = Array.from(document.querySelectorAll('.gatsby-image-wrapper'));
        allImageContainers.forEach(function (imageContainer) {
            const getImages = Array.from(imageContainer.querySelectorAll('IMG'));
            let backgroundImage;
            getImages.forEach((image)=>{
                if (image.hasAttribute('sizes')){
                    backgroundImage = image;
                }
            })
            const imgUrl = backgroundImage.src;
            if (imgUrl) {
                imageContainer.style.backgroundImage = 'url(' + imgUrl + ')';
                imageContainer.classList.add('compat-object-fit');
            };
        })
    }

Next I basically set the 'gatsby-image-wrapper' background image URL to the src of the initial image. I also add a class which I could target in the CSS.

    .gatsby-image-wrapper {
        &.compat-object-fit {
            background-size: cover;
            background-position: center center;
            img {
                display:none;
            }
        }
    }

The CSS is pretty simple. If the 'gatsby-image-wrapper' also has the class of 'compat-object-fit' (set in the JavaScript), set the background-size to cover and horizontally and vertically center it. Also display:none any img elements as we no longer need them.

My end solution looks like this...

Background Images

Hopefully this might help out other less experienced developers like myself.

Thanks for reading.