In today's web development landscape, creating engaging user experiences often requires capabilities that go beyond traditional animation. In this new article series, we'll explore how to use popular animation libraries, such as GSAP and Anime.js, to create delightful animations.
For this first gallery animation, I revisited a website I designed and developed in 2024 for the communications agency neuwaerts. While working on this project, I explored and experimented extensively with animation patterns and applications.

Installing GSAP and the ScrollTrigger Plugin
In order to replicate the horizontal gallery scrolling animation, we first need to install GSAP and the ScrollTrigger plugin. Since all plugins are confined to the gsap
package, we'll only have to install and manage one dependency per project.
npm install gsap
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);
Setting up the Gallery Structure
Once GSAP and the ScrollTrigger plugin are set up, we can start crafting the intended animation step by step. To start, we'll create a simple HTML gallery section identifiable by the .gallery
class attribute.
<section class="gallery">
<img
src="https://picsum.photos/720/720?random&2"
width="720"
height="480"
alt=""
/>
<img
src="https://picsum.photos/720/720?random&3"
width="720"
height="480"
alt=""
/>
<img
src="https://picsum.photos/720/720?random&4"
width="720"
height="480"
alt=""
/>
<img
src="https://picsum.photos/720/720?random&5"
width="720"
height="480"
alt=""
/>
<img
src="https://picsum.photos/720/720?random&6"
width="720"
height="480"
alt=""
/>
</section>
Performing the Gallery Animation
Next, we retrieve the gallery element and its last child element, then feed them into the gsap.to
tween. The tween then performs a scroll-bound animation that translates the x-axis of the gallery element to a value equal to the negative of its scroll width minus the width of its last child element.
const gallery = document.querySelector(".gallery");
if (gallery) {
const lastItem = gallery.children[gallery.children.length - 1];
const scrollTween = gsap.to(gallery, {
x: () => -(gallery.scrollWidth - lastItem.clientWidth),
ease: "none",
scrollTrigger: {
invalidateOnRefresh: true,
trigger: gallery,
start: "center center",
end: () => `+=${gallery.scrollWidth}px center`,
scrub: true,
pin: true,
},
});
}
Using the ScrollTrigger plugin, we configure the trigger, scrub, and pin behaviors. The Scrub feature links the animation progress to the scroll bar, and the Pin feature sticks the animated element to the screen, similar to a fixed position.
Adding Progressive Image Animations
To enhance the visual impact, each image receives its own scroll-triggered animation. These animations use the containerAnimation
property to synchronize with the main gallery movement.
const images = document.querySelectorAll(".gallery img");
for (const image of images) {
gsap.from(image, {
ease: "none",
opacity: 0,
filter: "blur(2rem)",
scrollTrigger: {
containerAnimation: scrollTween,
trigger: image,
start: "left right",
end: "center center",
scrub: true,
},
});
}
Although synchronizing animations may seem simple, determining the start and end points of an animation within its new context can be challenging. In this case, consider using the markers property of the ScrollTrigger plugin to visualize the endpoints.
And just like that, we implemented the foundation for a delightful, smooth, horizontal gallery scrolling animation using GSAP. From here on out, our animation journey has just begun, as we will delve into more animations and implementation patterns.
Considering Best Practices
In the next article in the series, we'll delve into the details of best practices regarding animations. For now, take a moment to consider the following aspects that we will discuss later:
- Accessibility: Use the
prefers-reduced-motion
media query to respect user preferences and ensure that keyboard navigation with clear focus indicators and comprehensive ARIA labels for screen readers works properly. - Content Strategy: Design robust fallback layouts that work seamlessly without JavaScript. Maintain the semantic HTML structure of critical content to ensure visibility and accessibility through traditional navigation patterns.
- Performance Testing: Continuously monitor frame rates across diverse devices, and use browser developer tools to identify potential bottlenecks. Consider using lazy loading strategies for large resources to maintain an optimal user experience.
- Responsive Design: Carefully design vertical layouts for mobile devices and implement touch-friendly controls for different screen sizes and interaction patterns. Test gesture-based navigation, and ensure horizontal scrolling works intuitively across various device orientations.
TL;DR
Explore how to implement a horizontal gallery scrolling animation with progressive image animations using GSAP and its ScrollTrigger plugin. Also, learn what to consider when working with animations for a future basis.