logo
Smooth Scroll Animations

Valentin Descombes

Beginner
~ 10 minutes

Smooth Scroll Animations

Learn how to create beautiful scroll-triggered animations

1

Setting up the project

In this tutorial, we'll create smooth scroll animations using the Intersection Observer API. First, let's set up our project structure.

Terminal
1
mkdir scroll-animations
2
cd scroll-animations
3
touch index.html style.css script.js

Next, let's create a basic HTML structure for our animation elements.

2

Creating the HTML structure

Let's create a simple HTML structure with multiple sections that we'll animate as they scroll into view.

index.tsx
1
<!DOCTYPE html>
2
<html lang="en">
3
<head>
4
<meta charset="UTF-8">
5
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6
<title>Smooth Scroll Animations</title>
7
<link rel="stylesheet" href="style.css">
8
</head>
9
<body>
10
<header>
11
<h1>Scroll Animations</h1>
12
<p>Scroll down to see the animations</p>
13
</header>
14
15
<section class="animate-section">
16
<h2>Fade In</h2>
17
<div class="content">
18
<p>This content will fade in when scrolled into view.</p>
19
</div>
20
</section>
21
22
<section class="animate-section">
23
<h2>Slide In From Left</h2>
24
<div class="content slide-left">
25
<p>This content will slide in from the left.</p>
26
</div>
27
</section>
28
29
<section class="animate-section">
30
<h2>Slide In From Right</h2>
31
<div class="content slide-right">
32
<p>This content will slide in from the right.</p>
33
</div>
34
</section>
35
36
<script src="script.js"></script>
37
</body>
38
</html>

💡 Tip

Make sure to add the "animate-section" class to any element you want to animate on scroll.

3

Adding JavaScript for scroll animations

Now let's add the JavaScript code that will power our scroll animations using the Intersection Observer API.

script.js
1
// Select all elements with the animate-section class
2
const sections = document.querySelectorAll('.animate-section');
3
4
// Configure the Intersection Observer
5
const observerOptions = {
6
root: null, // Use the viewport as the root
7
threshold: 0.1, // Trigger when 10% of the element is visible
8
rootMargin: '0px 0px -50px 0px' // Add a negative bottom margin to trigger earlier
9
};
10
11
// Create a new Intersection Observer instance
12
const observer = new IntersectionObserver((entries, observer) => {
13
entries.forEach(entry => {
14
// If the element is intersecting (visible)
15
if (entry.isIntersecting) {
16
// Add the 'animate' class to trigger the animation
17
entry.target.classList.add('animate');
18
19
// Stop observing the element after it's animated
20
// Remove this line if you want the animation to replay when scrolling back up
21
observer.unobserve(entry.target);
22
}
23
});
24
}, observerOptions);
25
26
// Start observing all sections
27
sections.forEach(section => {
28
observer.observe(section);
29
});

The highlighted lines show the most important configuration options for the Intersection Observer. You can adjust these values to control when the animations trigger as users scroll.

4

Adding CSS animations

Finally, let's add the CSS to create the animations that will be triggered when sections scroll into view.

style.css
1
* {
2
margin: 0;
3
padding: 0;
4
box-sizing: border-box;
5
}
6
7
body {
8
font-family: Arial, sans-serif;
9
line-height: 1.6;
10
color: #333;
11
}
12
13
header {
14
height: 100vh;
15
display: flex;
16
flex-direction: column;
17
justify-content: center;
18
align-items: center;
19
text-align: center;
20
padding: 2rem;
21
background: linear-gradient(135deg, #667eea, #764ba2);
22
color: white;
23
}
24
25
/* Base styles for sections */
26
.animate-section {
27
min-height: 60vh;
28
display: flex;
29
flex-direction: column;
30
justify-content: center;
31
padding: 4rem 2rem;
32
border-bottom: 1px solid #eee;
33
}
34
35
.animate-section:nth-child(odd) {
36
background-color: #f9f9f9;
37
}
38
39
.content {
40
max-width: 800px;
41
margin: 0 auto;
42
opacity: 0;
43
transform: translateY(20px);
44
transition: opacity 0.8s ease, transform 0.8s ease;
45
}
46
47
/* Animation styles - applied when the 'animate' class is added */
48
.animate-section.animate .content {
49
opacity: 1;
50
transform: translateY(0);
51
}
52
53
/* Special animations for slide effects */
54
.slide-left {
55
transform: translateX(-100px) !important;
56
}
57
58
.slide-right {
59
transform: translateX(100px) !important;
60
}
61
62
.animate-section.animate .slide-left,
63
.animate-section.animate .slide-right {
64
transform: translateX(0) !important;
65
}

ℹ️ Note

The CSS transitions create smooth animations when elements come into view. The default animation is a fade-in with slight upward movement, while the slide effects add horizontal movement.