Last update: February 2, 2021

How to make animated galleries with GSAP

In the previous tutorial, we learned how to create entrance animations and how to apply them to many elements at once.
This time we are going to have some fun with the Gallery element of Oxygen.

Let's create a gallery (Masonry style), and check the code in the Devtools to see how it is built:

The mistake

It looks like we have to use the .oxy-gallery-item class, so we can animate each image independently.
For the effect, we will make them zoom in, so we just set their scale to 0 :

const imgzoom1 = document.querySelectorAll("#gallery1 .oxy-gallery-item");

imgzoom1.forEach((element) => {

  	gsap.set(element, { scale:0 });
  
    gsap.to(element, {
        duration: 1.2,
        scale: 1,
        ease: "power2.out",
        scrollTrigger: {
            trigger: element,
            start: "top bottom-=100",
            end: "bottom top+=100",
            toggleActions: "play reverse play reverse"
        }
    });
})

The animation will work fine. No issue here. But let's study the scrollTrigger property :

We want each element start zooming when the top of the images reach the bottom of the screen (minus 100px so the effect will be visible even if we scroll slowly).

Check carefully the following gallery :

The problem

The 3 images at the top should appear at the same time as they are at the same vertical position.
If you scroll slowly, you will see that the one in the middle is coming before the two others.

And the image under it, is coming way too late!!! It doesn't work as expected...( and it's going to look weird on mobile).

The reason

It's because the element we chose to animate ( .oxy-gallery-item ) and the element we chose to trigger the animation ( .oxy-gallery-item ) are the same.
And because we have decided to change the size of this element, they don't appear at the same vertical position when they are smaller.
We don't notice it at first because all the images have a scale of 0, they are "invisible", but it becomes much more obvious when we change the scale to 0.5 :

That's why the 3 images at the top won't appear at the same time.

 

The solution

It's better to choose a container for the trigger, and a child of this container for the animation.

For our gallery, we will choose .oxy-gallery-item as the trigger, just like the previous gallery, but this time we will choose his child element  .oxy-gallery-item-contents for the animation.

So now the container won't be resized, it will keep his original size and position. Only the child will be animated:

Here is for the CSS:

#gallery2 .oxy-gallery-item .oxy-gallery-item-contents {
	visibility:hidden;
}

And the new JS code :

const imgzoom2 = document.querySelectorAll("#gallery2 .oxy-gallery-item");

imgzoom2.forEach((element) => {
	const contents = element.querySelectorAll(".oxy-gallery-item-contents") 

    gsap.set(contents, { scale:0 });
  
    gsap.to(contents, {
        duration: 1.2,
        autoAlpha:1,
        scale: 1,
        ease: "power2.out",
        scrollTrigger: {
            trigger: element,
            start: "top bottom-=100",
            end: "bottom top+=100",
            toggleActions: "play reverse play reverse"
        }
    });
})

Small galleries

For small galleries, we can make it simpler : we don't necessary  need to create a loop to have a different trigger for each image.
This time we only use the gallery itself as a trigger, and we animate each image with the stagger feature:

gsap.set("#gallery3 .oxy-gallery-item .oxy-gallery-item-contents", {
    scale: 0
});

gsap.to("#gallery3 .oxy-gallery-item .oxy-gallery-item-contents", {
    duration: 1.5,
    scale: 1,
    autoAlpha: 1,
    ease: "bounce.out",
    stagger: {
        grid: "auto",
        from: "random",
        each: .2
    },
    scrollTrigger: {
        trigger: "#gallery3",
        start: "top bottom-=100",
        end: "bottom top+=100",
        toggleActions: "play reset play reset"
    }

});
closealign-justifychevron-downcaret-up