How To Add Parallax Scrolling to Your Vue.js App

John Au-Yeung
Nov 28 · 5 min read
Photo by Humble Lamb on Unsplash

Parallax scrolling is the effect where the background image scrolls slower than the elements in the foreground, creating an illusion of depth of the page.

Websites often use this for informational pages, where you have some text in the foreground and an image in the background that scrolls more slowly to create a more interesting experience for the user.

https://www.mockplus.com/blog/post/parallax-scrolling-websites has some examples of web pages with parallax scrolling.

With React, it is quick and simple to create the parallax scrolling effect with the Vue-Parallaxy library, located at https://github.com/apertureless/vue-parallax.

In this article, we will make an app that displays a list of images in the background with tags text in the foreground. The images will be provided by the Pixabay API. You can register for an API key at Pixabay.

To start the project, we create the project by running:

npx @vue/cli create photo-app

Then we select ‘Manually select features’ then choose to include Babel and Vue Router.

We need to install Axios to get images from the Pixabay API, BootstrapVue for styling, and Vue-Parallaxy to create the parallax scrolling effect. To install the packages run:

npm i axios bootstra-vue vue-parallaxy

With all the packages installed, we can start building the app. To start, we add a mixin for making the HTTP requests. Create a mixins folder in the src folder, then in the folder, create requestsMixins.js . In the file, add:

const axios = require("axios");
const APIURL = "https://pixabay.com/api";
export const requestsMixin = {
methods: {
getImages(page = 1) {
return axios.get(
`${APIURL}/?page=${page}&key=${process.env.VUE_APP_API_KEY}`
);
}
}
};

Next in Home.vue , replace the existing code with the following:

<template>
<div class="page">
<div v-for="(img, i) of images" :key="i" class="parallax-container">
<parallax :speed-factor="0.5" direction="down" :parallax="true">
<div>
<img :src="img.largeImageURL" :alt="img.tags" style="image" />
<h1 class="parallax-title">{{img.tags}}</h1>
</div>
</parallax>
<br />
</div>
</div>
</template>
<script>
// @ is an alias to /src
import { requestsMixin } from "../mixins/requestsMixin";
import Parallax from "vue-parallaxy";
export default {
name: "home",
mixins: [requestsMixin],
components: {
Parallax
},
data() {
return {
images: []
};
},
methods: {
async getImagesByPage() {
const response = await this.getImages();
this.images = response.data.hits;
}
},
beforeMount() {
this.getImagesByPage();
}
};
</script>
<style>
.parallax-container {
position: relative;
height: 1000px;
}
.parallax-title {
position: absolute;
top: 30%;
left: 0;
right: 0;
padding: 20px;
color: white;
text-align: center;
}
.image {
height: 700px;
}
</style>

We include the Vue-Parallaxy component in this component by adding Parallax in the components object. Then we get the images by calling the this.getImages function from the requestsMixin we just created. We call the getImagesByPage function in the beforeMount hook to get the images when the page loads.

In the template, we use the parallax component provided by Vue-Parallaxy to create the parallax scrolling effect. The parallax serves as the container for the parallax effect. We make the speed of the scrolling different from the foreground with the speed-factor prop, we set the direction to down so that it scrolls down. parallax prop is set to true so that we get the different scrolling speed between the foreground and background.

We change the height of the parallax-container divs to the same height of 1000px, and the images to 700px to keep the spacing consistent.

In the component, we loop through the images and show some text from the Pixbay API. We position the text inside the photo by specifying:

<style>
.parallax-container {
position: relative;
}
.parallax-title {
position: absolute;
top: 30%;
left: 0;
right: 0;
padding: 20px;
color: white;
text-align: center;
}
</style>

We place the text in the center of the images and change the text color to white.

Next in App.vue , we replace the existing code with:

<template>
<div id="app">
<b-navbar toggleable="lg" type="dark" variant="info">
<b-navbar-brand href="#">Photo App</b-navbar-brand>
<b-navbar-toggle target="nav-collapse"></b-navbar-toggle> <b-collapse id="nav-collapse" is-nav>
<b-navbar-nav>
<b-nav-item to="/" :active="path == '/'">Home</b-nav-item>
</b-navbar-nav>
</b-collapse>
</b-navbar>
<router-view />
</div>
</template>
<script>
export default {
data() {
return {
path: this.$route && this.$route.path
};
},
watch: {
$route(route) {
this.path = route.path;
}
}
};
</script>
<style lang="scss">
.page {
padding: 20px;
}
</style>

We add some padding to the pages with the page class, and we add the BootstrapVue navigation bar to the top of the page. Also, we have the router-view so that we see the home page.

Next in main.js , we replace the existing code with:

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import "bootstrap/dist/css/bootstrap.css";
import "bootstrap-vue/dist/bootstrap-vue.css";
import BootstrapVue from "bootstrap-vue";
Vue.config.productionTip = false
Vue.use(BootstrapVue);
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')

to add the BootstrapVue libraries and styles to the app so we can use the code in our app and see the styling in the whole app.

Then in router.js , replace the existing code with:

import Vue from "vue";
import Router from "vue-router";
import Home from "./views/Home.vue";
Vue.use(Router);export default new Router({
mode: "history",
base: process.env.BASE_URL,
routes: [
{
path: "/",
name: "home",
component: Home
}
]
});

We added the home page route so that we can see the page we built.

Then in the root folder of the project, we add an .env file so store the API key:

VUE_APP_API_KEY='Pixabay API key'

We can use this keep by referencing process.env.VUE_APP_API_KEY like we have in the requestsMixin.js .

Next in index.html , replace the existing code with:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<title>Photo App</title>
</head>
<body>
<noscript>
<strong
>We're sorry but vue-parallax-scrolling-tutorial-app doesn't work
properly without JavaScript enabled. Please enable it to
continue.</strong
>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

to change the title.

Finally, run npm run serve , and you’ll see:

Notice that the bottom of the picture is different between the 2 pictures. The bottom is cut off in the top picture. We have achieved the desired effect of parallax scrolling.

JavaScript in Plain English

Learn the web's most important programming language.

John Au-Yeung

Written by

Web developer. Subscribe to my email list now at http://jauyeung.net/subscribe/ . Follow me on Twitter at https://twitter.com/AuMayeung

JavaScript in Plain English

Learn the web's most important programming language.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade