React: Background Images

Intro

Because of the way React uses webpack we can’t reference background images the way that we would in a normal static website. Here is the typical method of referencing a background image src.

.some-class {
  background-image: url("../../media/examples/lizard.png");
}

and a more complicated example with two background images.

.some-class {
  background-image: linear-gradient(
      rgba(0, 0, 255, 0.5),
      rgba(255, 255, 0, 0.5)
    ), url("../../media/examples/lizard.png");
}

However React does not let us makes references to images in the public folder, they must reference a source in the src folder, and then webpack makes a copy and changes the reference on build. Because of that we can’t put the background-image styling in our CSS or SASS files, we must inline these styles directly on the elements in our JSX.

Background Images in React

You’ll start by making a folder in your src directory to keep all your images, if you don’t already have one. Place your background images in there, and then you can reference them inside your chosen component.

src/components/App.js
import background3 from "../images/background3.svg"

and then inside your render function we inline style the background image like so

src/components/App.js
<div className="container">
  <div
    className="landing-wrapper"
    style={{ backgroundImage: `url(${background3})` }}  >
    <LandingHeader />
    <LandingHero />
    <LandingFeatures />
    <Footer />
  </div>
</div>

Note that we only use the template literal to make the URL a string, because backgroundImage gets transpiled by React into background-image. If you try to pass the whole style as a string it won’t work.

You could also inline the rest of the background image style properties, however I like to keep as much of my css as possible in my actual CSS files.

.landing-wrapper {
  background-size: auto;
  background-repeat: no-repeat;
  background-position: top left;
}

Changing Background Image for Mobile

Often we will want to change the background image based on the size of the device. One possible method of doing that is by using media breakpoints to change the height or width of the background image to 0.

/* Small devices (portrait tablets and large phones, 640px and up) */
@media only screen and (min-width: 640px) {
  .landing-wrapper {
    background-size: 0px;
    background-repeat: no-repeat;
    background-position: top center;
  }
}

/* Large devices (laptops/desktops, 1024px and up) */
@media only screen and (min-width: 1024px) {
  .landing-wrapper {
    background-size: auto;
    background-repeat: no-repeat;
    background-position: top left;
  }
}

or if you created a div specifically to add a background image, you could use the display:none property to toggle visibility at various breakpoints, and then have multiple divs that only exist to tie background images to.

Alternate Background Image Toggle Methods

There is a great article by Siri Lööf that has a clever method for swapping the background image based on a media query directly from the component.

Responsive Background Images Using React Hooks🍍

I’m copying the key code snippet here in case the original article gets nuked.

import React from 'react';
import './App.css';
import desktopImage from './pineapple-desktop.jpg';
import mobileImage from './pineapple-mobile.jpg';

const App = () => {
    const imageUrl = window.innerWidth >= 650 ? desktopImage : mobileImage;

    return (
        <div className="App" style={{backgroundImage: `url(${imageUrl})` }}>
            <div className="App-content">
                <h1>Pineapples</h1>
                <p>They are good</p>
            </div>
        </div>
    );
};

export default App;

Although this brings up a lot of other interesting possibilities. For example you could toggle background for a variety of reasons, like dark mode or user interactivity. Very cool Siri.