When doing front-end UI effects, animating elements based on their scrolling position is a very popular design, often using third-party plugins or libraries. In this tutorial, I’ll teach you how to do it using pure JavaScript and CSS.
Here’s a preview of the implementation:
We use CSS for the animations and JavaScript for the styles needed to trigger them. Let’s start by creating the layout.
Create a layout
We create the page layout using HTML, and then assign a generic class name to the elements that we want to animate, which the JavaScript uses to locate those elements. Here we specify js-scroll as the class name for the element that needs to be animated according to the scroll, and the HTML code is as follows:
<section class="scroll-container">
<div class="scroll-element js-scroll"></div>
<div class="scroll-caption">This animation fades in from the top.</div>
</section>
Copy the code
Add CSS styles
Let’s start with a simple fade animation:
.js-scroll {
opacity: 0;
transition: opacity 500ms;
}
.js-scroll.scrolled {
opacity: 1;
}
Copy the code
All jS-Scroll elements on the page will be hidden with an opacity of 0. When scrolling to the element area, add the.scrolled class name to it to make it visible.
Manipulating elements with JavaScript
With layout and style in hand, we now need to write a JavaScript function that assigns class names to elements as they scroll into the view.
Let’s break down the logic briefly:
- Get all on the page
js-scroll
The element - Make these elements fade out by default
- Checks if the element is in the window
- Allocates if the element is inside the window
scrolled
The name of the class
Get the target element
Get all js – scroll elements on a page, use the document. The querySelectorAll (a) :
const scrollElements = document.querySelectorAll('.js-scroll')
Copy the code
All target elements fade out by default
Iterate over these elements to fade them all out:
scrollElements.forEach((el) = > {
el.style.opacity = 0
})
Copy the code
Checks if the element is in the window
We can check if an element is in the user window by determining whether the distance between the element and the top of the page is less than the height of the visible part of the page.
In JavaScript, we use the getBoundingClientRect().top method to get the distance between the element and the top of the page, Using the window. The innerHeight or document. The documentElement. ClientHeight to obtain the height of the window.
We will create an elementInView function using the above logic:
const elementInView = (el) = > {
const elementTop = el.getBoundingClientRect().top
return (
elementTop <= (window.innerHeight || document.documentElement.clientHeight)
)
}
Copy the code
We can modify this function to detect whether the element scrolls x pixels to the page, or to detect the percentage of page scrolling.
const elementInView = (el, scrollOffset = 0) = > {
const elementTop = el.getBoundingClientRect().top
return (
elementTop <=
(window.innerHeight || document.documentElement.clientHeight) - scrollOffset
)
}
Copy the code
In this case, this function returns true if the element has been scrolled to the page by the number of scrolloffSets. Let’s change the parameter scrollOffset to a percentage:
const elementInView = (el, percentageScroll = 100) = > {
const elementTop = el.getBoundingClientRect().top
return (
elementTop <=
(window.innerHeight || document.documentElement.clientHeight) *
(percentageScroll / 100))}Copy the code
This section can define the logic according to its own specific needs.
Note: You can use the Intersection Observer API[2] to achieve the same effect, but it does not support IE.
Add the class name to the element
Now that we can detect if the element has been rolled to the page, we need to define a function to handle the display of the element — in this case we display the element by assigning the scrolled class name.
const displayScrollElement = (element) = > {
element.classList.add('scrolled')}Copy the code
Then, we’ll combine our previous logic with the displayScrollElement function and call that function on all jS-Scroll elements using the forEach method.
const handleScrollAnimation = () = > {
scrollElements.forEach((el) = > {
if (elementInView(el, 100)) {
displayScrollElement(el)
}
})
}
Copy the code
In addition, to reset an element to its default state when it is no longer in the view, we can define a hideScrollElement to do this:
const hideScrollElement = (element) = > {
element.classList.remove("scrolled");
};
const handleScrollAnimation = () = > {
scrollElements.forEach((el) = > {
if (elementInView(el, 100)) {
displayScrollElement(el);
} else{ hideScrollElement(el); }}Copy the code
Finally, we’ll pass the above method to the window’s scroll event listener so that it runs every time the user scrolls.
window.addEventListener('scroll'.() = > {
handleScrollAnimation()
})
Copy the code
We have implemented all the functions of scrolling animation.
Improve the sample
Please go back to the beginning of the article to see the renderings. As you can see, these elements appear in different animations. This is done by assigning different CSS animations to class names. The HTML for this example looks like this:
<section class="scroll-container">
<div class="scroll-element js-scroll fade-in"></div>
<div class="scroll-caption">Fade in dynamic effect</div>
</section>
<section class="scroll-container">
<div class="scroll-element js-scroll fade-in-bottom"></div>
<div class="scroll-caption">Cut into the top dynamic effect</div>
</section>
<section class="scroll-container">
<div class="scroll-element js-scroll slide-left"></div>
<div class="scroll-caption">Cut in the action effect from the left</div>
</section>
<section class="scroll-container">
<div class="scroll-element js-scroll slide-right"></div>
<div class="scroll-caption">Cut in the action effect from the right</div>
</section>
Copy the code
Here we assign different CSS class names to the elements with different dynamic effects. Here is the CSS code for these classes:
.scrolled.fade-in {
animation: fade-in 1s ease-in-out both;
}
.scrolled.fade-in-bottom {
animation: fade-in-bottom 1s ease-in-out both;
}
.scrolled.slide-left {
animation: slide-in-left 1s ease-in-out both;
}
.scrolled.slide-right {
animation: slide-in-right 1s ease-in-out both;
}
@keyframes slide-in-left {
0% {
transform: translateX(-100px);
opacity: 0;
}
100% {
transform: translateX(0);
opacity: 1; }}@keyframes slide-in-right {
0% {
transform: translateX(100px);
opacity: 0;
}
100% {
transform: translateX(0);
opacity: 1; }}@keyframes fade-in-bottom {
0% {
transform: translateY(50px);
opacity: 0;
}
100% {
transform: translateY(0);
opacity: 1; }}@keyframes fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1; }}Copy the code
Although we added different animation elements, we didn’t need to change the JavaScript code because the logic remained the same. This means we can add any number of different animations to the page without having to write new functions.
Use throttle to improve performance
Whenever we bind a function in the scroll listener, that function is called every time the user scrolls the page. Scrolling a 500px page results in a function being called at least 50 times. If we try to include a lot of elements on the page, it will cause our page to slow down significantly.
You can reduce the number of calls by using the “Throttle Function.” A throttling function is a higher-order function that calls the passed function only once in a specified time interval.
It’s especially useful for scroll events, because we don’t need to detect every pixel the user scrolls. For example, if we have a throttling function with a timer of 100ms, this function will be called only once for every 100ms scroll by the user.
The throttling function can be implemented in JavaScript like this:
let throttleTimer = false
const throttle = (callback, time) = > {
if (throttleTimer) return
// Mark this so that the function will not be executed twice
throttleTimer = true
setTimeout(() = > {
At the specified time, the incoming callback function is called
callback()
throttleTimer = false
}, time)
}
Copy the code
Then we can modify the Scroll event listener on the window object:
window.addEventListener('scroll'.() = > {
throttle(handleScrollAnimation, 250)})Copy the code
Now our handleScrollAnimation function is called every 250ms as the user scrolls:
To finish.
Reference:
- Developer.mozilla.org/en-US/docs/…
- Developer.mozilla.org/en-US/docs/…