Photo by Thomas Millot on Unsplash

Great websites feel responsive to a user’s interaction. One great way to do this is to react to someone scrolling down your page.

In addition to parallax components and scroll events, one great way to add a responsive touch is to make elements fade in as the view is scrolled.

In this daily tip, I took a look at how to implement this in Vue3 using scroll events and CSS transitions.

Here’s a screen capture of what we’ll be learning how to build in this tutorial.

Ready? Let’s start coding;

Styling Our Fade-In Elements

The very first thing that we want to do is build our template and style our component. In this example, we’re just going to be working with empty blocks to show how things could work.

So inside our template, we just want…

A wrapper container

A few full width elements

Some half width elements to add some variety

<template>

<div class='container'>

<div class='fade-in full-width' />

<div class='fade-in full-width' />

<div class='half-width fade-in' />

<div class='half-width fade-in' />

</div>

</template>

Then, to style them, we want to build a basic container and then style our blocks with some padding, colors, and the appropriate widths.

<style scoped>



.container {

width: 80%;

min-width: 450px;

margin: 0 auto;

}



.fade-in {

background-color: #2ecc71;

height: 500px;

margin-bottom: 50px;

opacity: 0;

transition: 0.3s all ease-out;

transform: scale(0.8);

box-sizing: border-box;

padding: 20px;

display: inline-block;

}

.full-width{

width: 100%;

}



.half-width {

width: 47.5%;

}



.half-width:nth-of-type(2n + 1) {

margin-right: 2.5%;

}



.half-width:nth-of-type(2n) {

margin-left: 2.5%;

}

</style>

One important thing to note is that all of our fade-in elements start with a default opacity of 0. We’ll handle fading them in with our scripts. We’re also going to be changing the scale of our element.

The fact that our fade in elements are given a transition property means that when we change the opacity and scale, it will smoothly transition between our two values — giving us the smooth effect that we want .

So, if we load our page, we shouldn’t see anything — but we should be able to scroll down our page because our elements are there, but just are completely transparent.

Let’s actually make them visible using some Javascript.

Making our elements fade in

For this tutorial, we’re going to be using the Vue Composition API — so inside our script, we first want to create our setup method and import some of our lifecycle hooks.

<script>

import { onMounted, onUnmounted } from 'vue'

export default {

setup () {



onMounted(() => {



})



onUnmounted(() => {



})

}

}

</script>

Then, let’s create an array of all of our fade-in elements. We can do this by using document.getElementsByClassName — however, this returns an HTMLCollection and we want an array so we can use Javascript’s Arr ay.from method to cast it.

onMounted(() => {

fadeInElements = Array.from(document.getElementsByClassName('fade-in'))

})

Now that we have an array of all the elements we want to fade in, we want to do a few things:

Iterate over them whenever the view is scrolled Determine if an element is visible If it is, fade it in and remove from our array

Alright.

First, we want to create our scroll listener when our component is mounted and remove it when our component is unmounted. Another thing we want to do, is call our handleScroll method when our component is mounted, so that the some content loads without the user having to scroll to see something.

var fadeInElements = []



onMounted(() => {

fadeInElements = Array.from(document.getElementsByClassName('fade-in'))

document.addEventListener('scroll', handleScroll)

handleScroll()

})



onUnmounted(() => {

document.removeEventListener('scroll', handleScroll)

})

Inside our scroll listener, let’s create a for loop that goes over the array of fade in elements that we created.

const handleScroll = (evt) => {

for (var i = 0; i < fadeInElements.length; i++) {

var elem = fadeInElements[i]

}

}

At this point, we need some sort of helper method to determine whether or not an element is visible. To do this, we’re going to be using the bounding rectangle of an element, which returns the size and position of an element relative to the viewport.

We’re also going to add a little buffer so at least 200px of the element has to be visible before it fades in. This will really enhance the effect because it ensures that site visitors will see what’s happening. Without this buffer, our fade in transition will trigger when 1 pixel of our element is on screen and a majority of it will be out of the viewport.

const isElemVisible = (el) => {

var rect = el.getBoundingClientRect()

var elemTop = rect.top + 200 // 200 = buffer

var elemBottom = rect.bottom

return elemTop < window.innerHeight && elemBottom >= 0

}

Back inside our scroll event listener, we want to see if our isElemVisible helper method is true for each element. If it is, we want to change the opacity and scale of our element and then remove it from our array.

for (var i = 0; i < fadeInElements.length; i++) {

var elem = fadeInElements[i]

if (isElemVisible(elem)) {

elem.style.opacity = '1'

elem.style.transform = 'scale(1)'

fadeInElements.splice(i, 1) // only allow it to run once

}

}

Now, if we go back to our app and check it out, you’ll see that as we scroll, elements become visible. Exactly what we want!

And we’re done, if you want!

So we have the fade in on scroll effect that we were looking for! There are so many ways that you can extend this effect, for example:

Have elements fade out when they’re scrolled off so that they can be faded in again

Add more advanced using CSS animations instead of transitions

Extract the logic into a custom directive so it can be reused across your entire project

As long as you got the hang of working with the scroll listener and CSS animations/transitions, the sky is really the limit.

I hope you learned a thing or two and can think of some cool ways to add some of these techniques into your own Vue projects.

Let me know if you have any questions, comments, or anything. I’d love to hear from you and see what you’ve made!