How to dynamically change the background image of a website in Vue/React

Khaldoun Al-nuaimi
3 min readFeb 23, 2022

The other day, I was doing a frontend mentor challenge. The challenge is quite simple for a junior web developer; however, one part that I really struggled with was changing the background image.

Frontend mentor space challenge — destination page

As seen in the two images above, the background image changes with each tab selected. In addition, different background images were provided for different viewport sizes ( mobile, tablet, and desktop). With traditional HTML, CSS, and JavaScript, developing this website would have been simple. Each HTML page would have its own background image, and a CSS media query would be used to change the images based on the viewport size. However, I am doing this challenge using Vue, so I had to come up with an alternative way.

From the above code, it can be seen that the navigation component isn’t defined inside each view, I believe redeclaring the navigation component inside each view would lead to less elegant code and a performance penalty. Hence, I declared the navigation component once inside the App component. I wrapped the navigation component and the router view inside a div and made that div the container for the background image.

The first step was to create a function to get the viewport size and return it accordingly. I just translated my viewport breakpoints into a JavaScript function which receives the width and height of the viewport as input variables.

I then declared the function to obtain the background size inside my app component and passed the window width and height as inputs. Make sure you do not declare the getBackgroundSize function inside any special hooks or function. We want this function to run as soon as the browser window loads so that we can determine the initial size of the browser window.

Now that we have figured out how to deal with the background size, we need to find a way to get the current route name. We can do this easily with Vue’s useRoute() or its react equivalent if you are using react. We can then simply watch the route for any changes and adjust the background image accordingly.

We've successfully figured out a way to change the background based on route and viewport size. However, we're not done yet. We need to account for users who view the website in split view, users who rotate their device while on our website, and users who like to play with the Developer Tools window inside their browsers (you know who you are). Using JavaScript's native resize event listener, we are able to watch for changes to the viewport. It is necessary to override our initial assignment of the viewportWidth and viewportHeight variables outside of the resize function by reassigning those variables inside it. To get the new background when the viewport is resized, we must also reassign the backgroundSize variable inside the resize function. Lastly, we must reassign the image variables so that the background image will change according to the new variables.

That’s all! We have managed to change the background size of our website dynamically and without redeclaring components ( the navigation component ) in every view instance. Are these methods hackish? Definitely! Thanks for reading. If I did not explain something very well, please reach out to me on Twitter.

You can find the full code for the App.vue below. I am also attaching the full GitHub repository of the entire website for this interested.

--

--