7 days of unlimited WordPress themes, plugins & graphics - for free!* Unlimited asset downloads! Start 7-Day Free Trial
  1. Web Design
  2. Parallax Scrolling

Create a Unique Scrolling Website With Locomotive Scroll & Tailwind CSS

Read Time: 12 mins

Have you ever wanted to build a unique single-page scrolling website yet didn’t know where to start? If so, don’t worry! Today we’re going to create together such a website. To achieve this, we’ll take advantage of Locomotive Scroll, a small and easy-to-use JavaScript library for cool scrolling effects.

Plus, to speed up the development process (and to create a responsive layout with minimal effort) we’ll put Tailwind CSS into play.

What We’re Building

As usual, before moving on, let’s examine the final result (scroll—or perhaps even better, view the demo on a large screen—and check the effects):

What is Locomotive Scroll?

Locomotive Scroll is one of the many JavaScript scrolling libraries that exist today. You might have already used some other ones in your projects, like ScrollTrigger.js and ScrollMagic.js. In actual fact, I covered a ScrollMagic example in a previous tutorial.

Here’s its definition as used on the Locomotive Scroll site:

“A simple scroll library used by developers at Locomotive. Built as a layer on top of ayamflow’s virtual-scroll, it provides smooth scrolling with support for parallax effects, toggling classes, and triggering event listeners when elements are in the viewport.”

Are you curious enough to explore the capabilities of this library? Let’s begin!

Getting Started With Locomotive Scroll

To get started with Locomotive Scroll, you have to include the following files in your project:

  • The locomotive-scroll.css file or its minified version
  • The locomotive-scroll.js file or its minified version

You can download them by visiting its GitHub repo, using a package manager (e.g. npm), or loading the necessary assets through a CDN (e.g. jsDelivr). For this tutorial, we’ll choose the last option.

As discussed in the introduction, for this demonstration, beyond the Locomotive files, we’ll also incorporate Tailwind CSS to create the page layout.

With that in mind, if you look under the Settings tab of our demo pen, you’ll see that there are two external CSS files and one external JavaScript file.

The required CSS filesThe required CSS filesThe required CSS files
The required JavaScript fileThe required JavaScript fileThe required JavaScript file

1. Structuring the Page

Locomotive Scroll comes with several different data attributes for manipulating the elements. We’ll use a lot of them, so at the end of this tutorial you’ll have a good grasp of what they do and how you can use them.

Let’s start by specifying a wrapper element with the data-scroll-container attribute. Inside it we’ll place the page sections and a back-to-top link. Later on, we’ll initialize the plugin by targeting this wrapper.

All page sections will have the data-scroll-section attribute. Plus, almost all of them will have an id attribute. This attribute will help us smoothly navigate to target sections through the menu and back-to-top links.

Here’s the initial page structure:

At this point, we’re ready to have a closer look at the important page sections.

Section #1

The first section will include a heading and a paragraph.

The layout of the first sectionThe layout of the first sectionThe layout of the first section

Another important thing here: by default, the back-to-top link won’t appear. As we scroll:

  • If the heading is in view, the link will be/remain invisible.
  • It will appear only when the heading isn’t in view.
The back-to-top link

To implement this functionality, we’ll pass the data-scroll, data-scroll-repeat, and data-scroll-call="toggleBackToTop" attributes to the heading. Let’s now discuss a little further the role of these attributes:

The job of the data-scroll attribute is to check if the element is in view. As soon as it appears for the first time, the plugin will add the is-inview class to it. This class won’t be removed any more. Notice also how the plugin modifies the element’s CSS transform property to apply the different effects.

The is-inview class added by Locomotive ScrollThe is-inview class added by Locomotive ScrollThe is-inview class added by Locomotive Scroll

The job of the data-scroll-repeat attribute is to check repeatedly if the element is in view. The plugin will toggle the is-inview class depending on the element’s position. In our case, we’ll use this attribute only in pair with the data-scroll-call attribute that needs it to work properly.

The job of the data-scroll-call attribute is to trigger Locomotive’s call event. The attribute value that can be anything we want is passed as a parameter to the event callback and allows us to do stuff when the target element enters or leaves the viewport. It’s a bit hard to explain it with words, so it’s better that you see the JavaScript code. We’ll work with it again in the upcoming sections. As said, remember that we’ll use it together with the data-scroll-repeat attribute.

Here’s how we structure this section:

Section #2

The second section will include the menu links.

The layout of the second sectionThe layout of the second sectionThe layout of the second section

To navigate smoothly to page sections upon clicking a link, we have to give the data-scroll-to attribute to the links.

Note: we’ll pass the same attribute to the back-to-top link.

Keep in mind that this attribute isn’t part of the docs at the time of this writing. If you’re wondering how I know about its existence, the answer is that I found it by checking the source code of the plugin’s GitHub Page.

The required data-scroll-to attribute for smooth scrolling

Alternatively, if you don’t want to use this attribute, you can achieve this functionality using some JavaScript scrolling methods.

Here’s how we structure this section:

Section #3

The third section will include a heading and some text.

The layout of the third sectionThe layout of the third sectionThe layout of the third section

As we scroll, we’ll pin the heading to the top. But, for how long? Well, until we scroll past its parent. At that point, the element will disappear as it will then be part of the normal document flow.

To implement this functionality, we’ll assign the data-scroll, data-scroll-sticky, and data-scroll-target="#about" attributes to the heading. Some notes:

  • As we already know, the data-scroll attribute will detect if our element is in view.
  • The data-scroll-sticky attribute will make it sticky in pair with the data-scroll-target attribute.
  • The value of the data-scroll-target attribute will determine the element’s initial and final sticky positions.
The sticky durationThe sticky durationThe sticky duration
We’ll follow the same technique in the sixth (clients) section, so we’ll skip that one.

Here’s how we structure this section:

Section #4

The fourth section will include two Unsplash images.

The layout of the fourth sectionThe layout of the fourth sectionThe layout of the fourth section

As we scroll, a parallax effect will happen. To be more specific, the first image will move four times faster than the second one.

To implement this functionality, we’ll pass the data-scroll and data-scroll-speed attributes to the images. The value of the second attribute will determine their scrolling speed. Here we’ll give data-scroll-speed="4.8" to the first image and data-scroll-speed="1.2" to the second one.

Here’s how we structure this section:

Section #5

The fifth section will include a heading and two text banners explaining our services.

The layout of the fifth sectionThe layout of the fifth sectionThe layout of the fifth section

As we scroll, multiple parallax effects will take place:

  • First, the heading’s letters will move at different speeds. Plus, each time they come into view, they will receive a random color from a list of predefined colors.
  • Second, the banners will move horizontally in different directions.

To implement this functionality, we’ll do the following:

We’ll assign the data-scoll, data-scroll-repeat, data-scroll-speed, and data-scroll-call="randomizeTextColor" attributes to the heading’s letters. As we want a parallax effect, the value of the data-scroll-speed attribute will vary for each letter. Remember the role of the data-scroll-call attribute. Here we’re saying: as the letters enter the viewport and Locomotive’s call event fires, do something. If you check the JavaScript section, you’ll notice that at this point the getRandomColor() function is firing. Optionally, here we can also put into action the data-scroll-delay attribute.

We’ll also assign the data-scroll, data-scroll-direction="horizontal", data-scroll-speed, and data-scroll-target="#services" attributes to the banners. The data-scroll-direction="horizontal" will move the elements horizontally on scroll. Next, by giving them opposite values for the data-scroll-speed attribute, we ensure that they will move in different directions (from left to right or right to left). Finally, the data-scroll-target="#services" attribute will determine when the horizontal animations should start. To understand it, try to put the id of another section e.g. data-scroll-target="#office" and reload the page. Notice that the animations start much sooner than they should be.

Here’s how we structure this section:

Section #7

The seventh section will include a call-to-action heading.

The layout of the seventh sectionThe layout of the seventh sectionThe layout of the seventh section

As we scroll, two things will happen:

  • First, each time the heading comes into view, it will receive a random color, like the previous example.
  • Second, we’ll animate each letter by creating another parallax (lerp) effect.

To implement this functionality, we’ll do the following:

We’ll assign the data-scoll, data-scroll-repeat, and data-scroll-call="randomizeTextColor" attributes to the heading. Remember that we’ve already met the data-scroll-call="randomizeTextColor" attribute. It’s perfectly fine to use it here as well.

And we’ll assign the data-scroll, data-scroll-delay, and data-scroll-speed="5" attributes to each letter. All letters will move five times faster than normal scrolling, yet with different delays. For example, the first letter will have data-scroll-delay="0.15" while the second one data-scroll-delay="0.095". This will create the lerp/staggering effect. Again you can see lerp effects in the plugin’s showcase example.

Here’s how we structure this section:

2. Initializing the Plugin

We’ve talked about many of the plugin’s features, yet we haven’t initialized it. Let’s do that now.

Here’s all the required JavaScript code:

Some quick notes:

  • We’ll keep its smooth behavior across all devices.
  • Notice the parameters of the call event callback. The first one (i.e. value) holds the values of the data-scroll-call attributes. Using an if condition, we check to see which values are active each time, then whether the associated elements enter or leave the viewport, and finally, we perform the desired actions.


Congrats, folks! We managed to build a parallax scrolling website thanks to Locomotive Scroll. Hopefully, this exercise has revealed the power of this tiny library and motivated you to start creating advanced scrolling effects effortlessly.

Here’s a reminder of what we built:

Don’t forget to give it some love ❤️!

Before closing, let me leave you with a few thoughts:

  • As with every technology/tool/library, the best way to learn Locomotive Scroll is through its docs. Go ahead, check the published example and use your browser tools to inspect its source code. Also, check its GitHub repo for issues, how active the project is, how other people use the library, or just for taking some ideas. If you feel more adventurous, check the plugin’s native code. Here you’ll learn things like what parameters a function (e.g. the callback of the call event) can accept, etc.
  • Scrolling effects can decrease a website’s performance. Besides this fact, the more complex the effects, the more risk there is they will encounter issues across different browsers/devices. For example, on mobile devices I would avoid using the horizontal animations we covered.
  • For even more powerful effects, you can combine Locomotive Scroll with other animation libraries like GSAP and barba.js.

Last but not least, a big thanks to Locomotive developers for this plugin! As always, thanks a lot for reading, and be sure to share with us your Locomotive projects!

Keep on Scrolling

Check out these other tutorials to learn more about JavaScript and scrolling:

Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Web Design tutorials. Never miss out on learning about the next big thing.
Scroll to top
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.