How to Animate Objects When Shown Inside Viewport with VueJS and Animate.css

Jian Jye • October 29, 2019

vuejs

Animate.css has made animation superbly simple for all web developers. One problem however is that, it will always animate the objects on pageload. If our elements are below the fold / viewport, then it would have already been animated by the time we scroll to that position.

With the help of VueJS and Vue Observe Visibility plugin however, we can add some finer control as to when to animate our objects.

The logic behind this is that, the Vue Observe Visibility plugin would do the necessary calculations to see if an element is visible in the viewport, then VueJS would set the necessary flag to animate the object accordingly.

With this, we can make sure that the animations would only be triggered when they are visible.

It's very simple. Let's begin!


Step 1. Include VueJS, Vue Observe Visibility Plugin and Animate.css

Let's include all the necessary files into our web page.

<html>
    <head>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <script src="https://unpkg.com/vue-observe-visibility/dist/vue-observe-visibility.min.js"></script>
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.7.2/animate.min.css">
    </head>
    <body>
        ...
    </body>
</html>

If you are not using Tailwind CSS, you may need these 2 CSS classes to be added in <head>.

<style>
    .visible { visibility: visible; }
    .invisible { visibility: hidden; }
</style>

Step 2. Basic Example

Can you see this animation?
<html>
    <head>...</head>
    <body>
        <div id="demo">
            <div v-observe-visibility="{ callback: isViewableNow, once: true }" :class="{ 'visible animated slideInRight': showAnimation, 'invisible': !showAnimation }">
                Can you see this animation?
            </div>
        </div>

        <script>
            var demo = new Vue({
                el: '#demo',
                data: {
                    showAnimation: false,
                },
                methods: {
                    isViewableNow(isVisible, entry) {
                        this.showAnimation = isVisible;
                    }
                }
            });
        </script>
    </body>
</html>

Step 3. Detailed Explanations

So what happened there? Let's us delve into how this works.

Vue Observe Visibility

First, we made Vue Observe Visibility plugin to check this particular object by adding the v-observe-visibility attribute. It takes a function callback that we named isViewableNow. You can name this function anything as long as it matches what you have declared in Javascript.

Then we made sure it is to be called only once by setting once: true. Otherwise your animation would restart itself everytime it's viewable in your viewport, which may or may not be what you want.

<div v-observe-visibility="{ callback: isViewableNow, once: true }" ...></div>

VueJS + Animate.css

The second part of the same div, we have the VueJS :class attribute.

If you are not familiar with VueJS, what :class does is let VueJS decide if it should add or remove any classes based on some value, which in our case is the showAnimation variable.

When the object is not visible, we add in the CSS class invisible to hide the element. When it's visible, we add in the CSS class visible to show the element.

In addition to visible, we are also adding in the Animate.css classes animated slideInRight. This is to trigger the animation effects as we desired when the object becomes visible.

<div ... :class="{ 'visible animated slideInRight': showAnimation, 'invisible': !showAnimation }"></div>

Step 4. Animating Multiple Objects

Can you see this animation part 2?
Can you see this animation part 3?

Now what if you need to animate more than 1 object on the same page? Having to declare multiple callbacks doesn't seem like such a good idea.

One way is to make the isViewableNow method reusable. Thankfully it accepts a third optional argument that we can use to set our objects visibilities.

The new codes would look like this:

<html>
    <head>...</head>
    <body>
        <div id="demo2">
            <div v-observe-visibility="{ callback: (isVisible, entry) => isViewableNow(isVisible, entry, 'a') }" :class="{ 'visible animated slideInRight': showAnimationFor.a, 'invisible': !showAnimationFor.a }">
                Can you see this animation part 2?
            </div>

            <div v-observe-visibility="{ callback: (isVisible, entry) => isViewableNow(isVisible, entry, 'b') }" :class="{ 'visible animated slideInLeft': showAnimationFor.b, 'invisible': !showAnimationFor.b }">
                Can you see this animation part 3?
            </div>
        </div>

        <script>
            var demo = new Vue({
                el: '#demo2',
                data: {
                    showAnimationFor: {
                        a: false,
                        b: false,
                        c: false,
                    }
                },
                methods: {
                    isViewableNow(isVisible, entry, section) {
                        this.showAnimationFor[section] = isVisible;
                    }
                }
            });
        </script>
    </body>
</html>

Step 5. Detailed Explanations Part 2

So what have we done?

First we added a third argument for our isViewableNow method to show which section is being triggered at the moment.

// V2
isViewableNow(isVisible, entry, section) {
    this.showAnimationFor[section] = isVisible;
}

// V1
isViewableNow(isVisible, entry) {
    this.showAnimation = isVisible;
}

Then we updated the callback codes for isViewableNow into the new form, allowing the callback to take the new third argument for our sections.

// V2
<div v-observe-visibility="{ callback: (isVisible, entry) => isViewableNow(isVisible, entry, 'a') }" ...></div>

// V1
<div v-observe-visibility="{ callback: isViewableNow, once: true }" ...></div>

Finally we updated our :class attribute to check the respective sections on the new showAnimationFor object.

// V2
<div ... :class="{ 'visible animated slideInRight': showAnimationFor.a, 'invisible': !showAnimationFor.a }"></div>

// V1
<div ... :class="{ 'visible animated slideInRight': showAnimation, 'invisible': !showAnimation }"></div>

And with these minor modifications, you can have as many objects to be animated as you like!


Closing

That's all! It's surprisingly simple isn't it?

I hope you find this guide helpful.

References:

Sign up for our newsletter