Written by Isaac Okoro✏️
Scrolling animations are implemented on many web pages, particularly those with large content, to make scrolling better and less tedious. Scrolling animations are now common on the web because of the introduction of devices capable of handling them. There are lots of different types of scroll animations: sticky scroll, smooth scroll, and CSS parallax, to name a few.
Though some of the aforementioned scroll animations like CSS parallax can be implemented with CSS, you might need libraries like GSAP or Framer Motion to handle more complex animations in your project.
This article will take a look at the react-locomotive-scroll
package, or Locomotive Scroll as we’ll call it, a library for handling and creating different scroll animations in React.
- What is Locomotive Scroll?
- Exploring Locomotive Scroll’s features
- Building a portfolio website with Locomotive Scroll features
- Customizing Locomotive Scroll components with React
- Further implementations of Locomotive Scroll
- Controversies around Locomotive Scroll and scroll jacking
What is Locomotive Scroll?
Locomotive Scroll is a React scroll library that builds on ayamflow's virtual-scroll, a library used to create custom scrollers that support touch and keyboard. Locomotive Scroll provides support for various forms of scrolling animations, including smooth scrolling, animated page overlays, and parallax effects.
Without further ado, let’s set up our workspace and dive in using the Locomotive Scroll package in a React application. Run the command below to scaffold a new React project:
yarn create react-app <Name-of-your-app>
Next, change the directory into the project folder and install the Locomotive Scroll package using the command below:
cd locomotive-scroll-react && yarn add locomotive-scroll react-locomotive-scroll
Clear out the unnecessary files in the src
folder and navigate to the App.js
file. Replace the entire boiler code with the code block below:
import './App.css';
function App() {
return (
<main>
<section className='intro'>
<h1>This is the Introduction section</h1>
</section>
<section className='contents'>
<h1>I Love React</h1>
</section>
<section id="stick">
<h1>
Hey I'm Sticky
</h1>
<p>other contents</p>
<p>other contents</p>
<p>other contents</p>
<p>other contents</p>
<p>other contents</p>
<p>other contents</p>
<p>other contents</p>
<p>other contents</p>
</section>
<section className='footer'>
<h1>Let's end the application with this Footer</h1>
</section>
</main>
);
}
export default App;
Next, replace the entire the App.css
with the styles below:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.App {
text-align: center;
}
h1{
font-size: 5rem;
font-weight: bolder;
}
p {
font-size: 3rem;
margin: 1rem;
}
section {
height: 100vh;
color: white;
display: flex;
align-items: center;
justify-content: center;
}
.intro{
background-color: black;
}
.contents {
background-color: goldenrod;
}
#stick {
background-color: rgb(71, 14, 64);
display: flex;
height: 100vh;
flex-direction: column;
justify-content: center;
align-items: center;
}
.footer {
background-color: whitesmoke;
color: seagreen;
}
After running the development server with yarn start
, we should get something similar to the GIF below:
Exploring Locomotive Scroll’s features
This section will cover some features in the Locomotive Scroll package and how to implement them into our application.
Smooth scrolling
Smooth scrolling is one of the biggest features of the Locomotive Scroll package. This gives the application a swift and fluid feel when scrolling through various sections. Let’s see how this will look in our application.
Locomotive Scroll has some custom attributes that possess some styles. When added to a component, those styles give the component “locomotive” features.
Add the styles below to your App.css
file, as recommended by the react-locomotive-scroll
package’s documentation:
html.has-scroll-smooth {
overflow: hidden;
}
html.has-scroll-dragging {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.has-scroll-smooth body {
overflow: hidden;
}
.has-scroll-smooth [data-scroll-container] {
min-height: 100vh;
}
[data-scroll-direction="horizontal"] [data-scroll-container] {
height: 100vh;
display: inline-block;
white-space: nowrap;
}
[data-scroll-direction="horizontal"] [data-scroll-section] {
display: inline-block;
vertical-align: top;
white-space: nowrap;
height: 100%;
}
.c-scrollbar {
position: absolute;
right: 0;
top: 0;
width: 11px;
height: 100%;
transform-origin: center right;
transition: transform 0.3s, opacity 0.3s;
opacity: 0;
}
.c-scrollbar:hover {
transform: scaleX(1.45);
}
.c-scrollbar:hover, .has-scroll-scrolling .c-scrollbar, .has-scroll-dragging .c-scrollbar {
opacity: 1;
}
[data-scroll-direction="horizontal"] .c-scrollbar {
width: 100%;
height: 10px;
top: auto;
bottom: 0;
transform: scaleY(1);
}
[data-scroll-direction="horizontal"] .c-scrollbar:hover {
transform: scaleY(1.3);
}
.c-scrollbar_thumb {
position: absolute;
top: 0;
right: 0;
background-color: black;
opacity: 0.5;
width: 7px;
border-radius: 10px;
margin: 2px;
cursor: -webkit-grab;
cursor: grab;
}
.has-scroll-dragging .c-scrollbar_thumb {
cursor: -webkit-grabbing;
cursor: grabbing;
}
[data-scroll-direction="horizontal"] .c-scrollbar_thumb {
right: auto;
bottom: 0;
}
With that done, navigate to the App.js
file and import LocomotiveScrollProvider
from react-locomotive-scroll
, as well as the useRef
hook into the App.js
file.
The react-locomotive-scroll
package exports a provider component that acts as a top-level wrapper to our application, thereby granting it locomotive scrolling features.
Next, wrap up the return
statement of App.js
with LocomotiveScrollProvider
and add some attributes to our tags:
import { LocomotiveScrollProvider } from "react-locomotive-scroll";
import { useRef } from "react";
function App() {
const ref = useRef(null);
const options = {
smooth: true,
}
return (
<LocomotiveScrollProvider options={options} containerRef={ref}>
<main data-scroll-container ref={ref}>
<section className="intro" data-scroll-section>
<h1>This is the Introduction section</h1>
</section>
<section className="contents" data-scroll-section>
<h1>I Love React</h1>
</section>
<section className="footer" data-scroll-section>
<h1>Let's end the application with this Footer</h1>
</section>
</main>
</LocomotiveScrollProvider>
);
}
In the code block above, we created and assigned our options
object to the options
prop and the useRef
hook to the ref
prop in LocomotiveScrollProvider
.
The options
prop takes an object as a parameter used in customizing the scroll behavior. We’ve also added some attributes to our tags.
The attribute is the data-scroll-container
that’s always added to the top-level tag, thereby giving its children components smooth scrolling ability.
The data-scroll-section
attribute is added to every component to initialize it with Locomotive Scroll and prevent some messy behavior.
With that done, we should be able to achieve the smooth scrolling behavior shown below:
Animated page overlays
With the react-locomotive-scroll
package, pages and sections can be manipulated to make them appear over other sections when scrolling. Let’s see how this feature works by writing some code:
<main data-scroll-container ref={ref}>
<section
className="intro"
data-scroll //This attribute makes this section an independent scrollable container
data-scroll-speed="4"
data-scroll-section
>
<h1>This is the Introduction section</h1>
</section>
...
</main>
In the code block above, we added two attributes to our introduction section tag: the data-scroll
, which makes the section an independent scrollable container, and the data-scroll-speed
, which determines the scroll speed of the section.
Together, the two attributes give a nice, animated, scroll-out overlay to the introduction part of the application as shown in the GIF below:
Floating contents
Floating elements coming into view when scrolling is so cool and can be easily achieved using react-locomotive-scroll
! Let’s implement this by updating our App.js
code:
<main data-scroll-container ref={ref}>
...
<section className="contents" data-scroll-section>
<h1
data-scroll
data-scroll-direction="horizontal"
data-scroll-speed="9"
>
I Love React
</h1>
<h1
data-scroll
data-scroll-direction="vertical"
data-scroll-speed="9" // Values provided here affect the animations
>
That's why I code every day
</h1>
</section>
...
In the code block above, we’re leveraging the data-scroll-direction
and data-scroll-speed
attributes. They give the elements a floating animation as specified by the value provided to the data-scroll-speed
attribute:
Sticky scroll
Let’s talk about making a text or component stick to its position when scrolling. I think it looks more creative when trying to pass information or when improving the user’s feel and experience. Let’s see how we can achieve this using the locomotive-scroll
package. Add the code below to the App.js
file:
<main data-scroll-container ref={ref}>
...
<section id="stick" data-scroll-section>
<h1
data-scroll
data-scroll-speed="5"
data-scroll-sticky // Attibute that enables the sticky scroll
data-scroll-target="#stick"
>
Hey I'm Sticky
</h1>
<p>other contents</p>
<p>other contents</p>
<p>other contents</p>
<p>other contents</p>
<p>other contents</p>
<p>other contents</p>
<p>other contents</p>
<p>other contents</p>
</section>
...
</main>
In the code block above, we gave our h1
text the sticky attribute and assigned its target environment to the sticky section. This data-scroll-target
attribute confines its child to the section provided. Now, we have this:
Scrolling into view classes
Have you ever thought of adding your own custom animation when scrolling into view? The react-locomotive-scroll
package has got you covered. It gives you the flexibility to call other classes when scrolling into view.
Let’s demonstrate this with a simple fade-in animation. Add the styles below to the App.css
file:
.op-class{
opacity: 0;
}
.fadeIn {
opacity: 1;
transition: opacity 4s ;
}
Next, update the footer section:
<main data-scroll-container ref={ref}>
...
<section className="footer" data-scroll-section>
<h1
className="op-class"
data-scroll
data-scroll-class="fadeIn"
data-scroll-repeat="true"
data-scroll-speed="2"
>
Let's end the application with this Footer
</h1>
</section>
</main>
In the code block above, we added our op-class
and also added the data-scroll-class
attribute. op-class
triggers a class when its element is scrolled into view, and data-scroll-repeat
makes the entire process loop by removing the class when it’s not in view.
This combination of these attributes creates a nice fade-in animation to the footer section of our application, as shown below:
Super speed scrolling
The Locomotive Scroll package also gives you the ability to determine the scroll speed of your entire application. Super cool right?
Let’s give our application some super scrolling speed.
Update the options object in the App.js
:
const options = {
smooth: true,
multiplier: 9, //added this
};
We added the multiplier property to our options object as shown in the code block above. The multiplier property takes in a number to determine the speed of the application.
The GIF below displays the speed of our application after setting up our multiplier:
Building a portfolio website with Locomotive Scroll features
Let’s put all that we’ve learned so far into building a portfolio website! Here we’ll implement a couple of Locomotive Scroll’s features.
First, clone and run the project’s starter file from GitHub. The starter file comes with basic components and styling as seen in the GIF below. We will implement the various features of Locomotive Scroll as we go:
We will start by importing the useRef
hook and LocomotiveScrollProvider
into the App.js
file and wrapping our return
statement with LocomotiveScrollProvider
. After this, we‘ll create our options
object that’ll be passed to LocomotiveScrollProvider
:
import { useRef } from "react";
import { LocomotiveScrollProvider } from "react-locomotive-scroll";
const options = {
smooth: true,
multiplier: 3,
}
return (
<LocomotiveScrollProvider
options={options}
containerRef={ref}
>
<main data-scroll-container ref={ref}>
<Introduction />
<Work />
<Message />
</main>
</LocomotiveScrollProvider>
);
Customizing Locomotive Scroll components with React
Let's get started customizing our portfolio with some nice scroll effects for each section. Let’s start with the “Introduction” component on the site. Head over to the src/components/intro/Introduction.jsx
file:
// src/components/intro/Introduction.jsx
const Introduction = () => {
return (
<section
className="intro-section"
data-scroll-section
data-scroll
data-scroll-speed="6"
>
<div className="intro-image">
<img src={image} height={700} alt="profile" />
</div>
<div className="intro-title">
<h1 data-scroll data-scroll-speed="9">
Isaac Junior
<br />A Frontend Engineer and Technical writer with a deep focus on
creating pixel-perfect designs
</h1>
</div>
</section>
);
};
In the code block above, we’ve initialized our component with an overlay effect using the data-scroll
and data-scroll-speed
attributes. We also gave the text some scroll speed to create a scroll-disappearing effect.
Next, head over to the src/components/work/Work.jsx
file and update the code to the one below:
// src/components/work/Work.jsx
const Work = () => {
return (
<section id="case-stick" data-scroll-section className="work-section">
<p
className="case"
data-scroll
data-scroll-sticky
data-scroll-target="#case-stick"
>
CASE STUDIES <br />
Latest Works
</p>
...
</section>
);
};
In the code block above, we’re making our section a scroll container using the data-scroll-section
attribute. We’re also making our text sticky when scrolling using the data-scroll-sticky
and data-scroll-target
attributes, targeting our section’s id
.
It would be nice if we could give our card a little scroll effect. Head over to the src/components/Card.jsx
file and update the file with the code below:
// src/components/Card.jsx
function Card(props) {
const {image, title, description} = props;
return (
<div
data-scroll
data-scroll-speed="9"
className="card container"
>
<div className="cardImg">
<img src={image} alt="img" />
</div>
<div className="cardContent">
<p className="cardTitle">{title}</p>
<p className="cardDesc">{description}</p>
</div>
</div>
);
}
In the code block above, we’re initializing our card with the data-scroll
attribute and giving our card component some scroll speed.
Finally, let’s customize our “Message” section. But before we head over there, add the styles below to the src/components/message/message-style.css
file:
// src/components/message/message-style.css
.op-class{
opacity: 0;
}
.fadeIn {
opacity: 1;
transition: opacity 4s ;
}
We will use the styles above to create a nice fade-in animation for this section. Now, head over to the src/components/message/Message.jsx
file and update the code to the one below:
// src/components/message/Message.jsx
const Message = () => {
return (
<section data-scroll-section className="message-section">
<p
data-scroll
data-scroll-direction="horizontal"
data-scroll-speed="2"
className="message"
>
Drop a Message
</p>
<div
className=" op-class"
data-scroll
data-scroll-repeat="true"
data-scroll-class="fadeIn"
data-scroll-speed="4"
>
<input type="text" name="fullName" placeholder="Full Name" id="" />
<input type="text" name="email" placeholder="Enter Email" id="" />
<textarea name="" placeholder="Message" id="" />
</div>
</section>
);
};
In the code block above, we called the fadeIn
class when the inputs are about to scroll into view. We also added the data-scroll-repeat
attribute and set it to true to enable the fadeIn
animation to repeat itself continuously.
With that done, you should be able to see the results of the Locomotive Scroll library on our new portfolio website, as shown below:
Further implementations of Locomotive Scroll
The Locomotive Scroll view has tons of options and attributes. Combinations can be made between these attributes to get more amazing animations. You can head over to the Locomotive Scroll docs to learn more.
Controversies around Locomotive Scroll and scroll jacking
In web development, events are triggers that are fired off to notify changes, either from user interactions (click, scroll, or form submission), browser changes (page load), environmental changes (low battery), and other causes.
Anything that causes an adverse effect to an event is known as jacking. There are many forms of jacking in web development, including web jacking, clickjacking, scroll jacking, and more. The focus of this section will be on scroll jacking and Locomotive Scroll.
Scroll jacking takes control of the scroll motion of the browser and changes the expected scroll motion to some other unexpected one. Scroll jacking makes it hard to navigate a page, as the expected up/down or side-to-side behavior is repurposed with unexpected behavior.
One example of this is stopping a user from scrolling past a piece of text for a few seconds to make sure they read the text. It could also be momentarily disabling the scroll to the “I accept the terms and conditions” section altogether to make sure the user reads through the terms and conditions of a particular software.
Scroll jacking is a controversial practice that has negative effects on usability, accessibility, and performance.
Locomotive Scroll uses scroll jacking to create a more appealing and fluid experience when scrolling, while also providing beautiful and advanced animations, as stated on the official website. The decision to enable scroll jacking when building an application should be made responsibly so as to avoid negative implications.
Conclusion
In this article, we learned how to use the react-locomotive-scroll
package to give our websites a better scroll behavior. We looked at how to provide components with their own custom scroll behavior, as well as the relationship between scroll jacking and Locomotive Scroll.
Here is the link to the source code on GitHub and a link to the hosted application on Netlify.
Cut through the noise of traditional React error reporting with LogRocket
LogRocket is a React analytics solution that shields you from the hundreds of false-positive errors alerts to just a few truly important items. LogRocket tells you the most impactful bugs and UX issues actually impacting users in your React applications.
LogRocket automatically aggregates client side errors, React error boundaries, Redux state, slow component load times, JS exceptions, frontend performance metrics, and user interactions. Then LogRocket uses machine learning to notify you of the most impactful problems affecting the most users and provides the context you need to fix it.
Focus on the React bugs that matter — try LogRocket today.
Top comments (0)