How To Add Parallax Scrolling to Your Vue.js App
Tags: vue, javascript, webdev, html
Published: 2020-01-15 03:02:03

**Subscribe to my email list now at http://jauyeung.net/subscribe/**

**Follow me on Twitter at https://twitter.com/AuMayeung**

**Many more articles at https://medium.com/@hohanga**

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](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](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](https://pixabay.com/api/docs/).

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

```bash
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:

```bash
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:

```javascript
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:

```javascript
<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:

```scss
<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:

```javascript
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:

```javascript
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:

```javascript
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:

```html
<!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.