Build a “button-to-modal” animation with GSAP

Build a “button-to-modal” animation with GSAP


In this new tutorial, we’ll continue working with GSAP and learn how to create an easy-to-follow, attractive, button-to-modal animation. This type of animation is ideal for toggling modal forms.

Without more intro, let’s explore the final result!

1. Begin with the page markup

Inside a wrapper, we’ll place the modal trigger and an empty element. We’ll also wrap the button content within a span element.

1

class="wrapper">

2
  
3
    Contact Us
4
  
5
  

class="next">

6

Regarding the modal structure, we’ll borrow it along with most of its styles from a previous tutorial:

1

class="modal">

2
  

class="modal-dialog">

3
    
4
5
    
6
    
class="modal-content">...
7
  
8

2. Add the CSS

The button and the empty element will have fixed dimensions and the same background color.

The button will be 190px x 50px while its sibling will be 50px x 50px.

In addition, the empty element will be absolutely positioned inside its parent element and hidden by default as the button will have a higher z-index value.

Here are the related styles using CSS nesting:

1
/*CUSTOM VARIABLES HERE*/
2

3
.wrapper {
4
  position: relative;
5

6
  > * {
7
    background: var(--black);
8
  }
9

10
  .open-modal {
11
    position: relative;
12
    display: block;
13
    width: 190px;
14
    height: var(--base-width);
15
    color: var(--white);
16
    border-radius: 30px;
17
    font-weight: bold;
18
    z-index: 1;
19
  }
20

21
  .next {
22
    position: absolute;
23
    top: 50%;
24
    left: 50%;
25
    transform: translate(-50%, -50%);
26
    width: var(--base-width);
27
    aspect-ratio: 1;
28
    border-radius: 50%;
29
  }
30
}

The modal will be a fixed positioned element and hidden by default.

Here are all its styles:

1
/*CUSTOM VARIABLES HERE*/
2

3
.modal {
4
  position: fixed;
5
  left: 0;
6
  bottom: 0;
7
  right: 0;
8
  align-items: center;
9
  justify-content: center;
10
  background: var(--black);
11
  visibility: hidden;
12
  opacity: 0;
13
  z-index: 2;
14

15
  &,
16
  .close-modal {
17
    top: 0;
18
    color: var(--white);
19
  }
20

21
  .modal-dialog {
22
    display: flex;
23
    width: 100%;
24
    height: 100vh;
25
    overflow: auto;
26
  }
27

28
  .modal-content {
29
    max-width: 800px;
30
    padding: 1rem;
31
    margin: auto;
32

33
    p + p {
34
      margin-top: 1rem;
35
    }
36
  }
37

38
  .close-modal {
39
    position: absolute;
40
    right: 30px;
41
    font-size: 2rem;
42
  }
43
}

3. Add the JavaScript

Once the button is clicked, we’ll hide it and display the modal. To make this process smooth, we’ll initialize a GSAP timeline that will perform the following actions:

  • Hide the button content.
  • Set the button width equal to its sibling width.
  • Scale the empty element up to a point where it covers the whole page size. To ensure this, we’ll perform some logic inside the scaledValues() function.
  • Show the modal.
  • As soon as the timeline ends, we’ll add the is-visible class to the modal.

Here’s the related JavaScript code:

1
const openModal = document.querySelector(".open-modal");
2
const span = openModal.querySelector("span");
3
const next = openModal.nextElementSibling;
4
const modal = document.querySelector(".modal");
5
const closeModal = modal.querySelector(".close-modal");
6
const baseWidth = 50;
7
const IS_VISIBLE_CLASS = "is-visible";
8

9
function scaledValue() {
10
  let windowWidth = window.innerWidth;
11
  const windowHeight = window.innerHeight;
12

13
  if (windowHeight > windowWidth) {
14
    windowWidth = windowHeight;
15
  }
16
  const toScale = windowWidth / baseWidth + 10;
17
  return Math.ceil(toScale);
18
}
19

20
openModal.addEventListener("click", function () {
21
  const tl = gsap.timeline({
22
    onComplete: () => modal.classList.add(IS_VISIBLE_CLASS)
23
  });
24
  tl.to(span, { opacity: 0, duration: 0.25 })
25
    .to(this, { width: baseWidth })
26
    .to(next, { scale: scaledValue() })
27
    .to(modal, { autoAlpha: 1 });
28
});

Once the .close-modal button is clicked or the ESC key is pressed, we’ll reverse the logic. In this case, we’ll set a new timeline and reverse the previous animations.

Here’s the JavaScript code responsible for closing the modal:

1
...
2

3
closeModal.addEventListener("click", function () {
4
  const tl = gsap.timeline({
5
    onComplete: () => modal.classList.remove(IS_VISIBLE_CLASS)
6
  });
7
  tl.to(modal, { autoAlpha: 0 })
8
    .to(next, { scale: 1 })
9
    .to(openModal, { width: 190 })
10
    .to(span, { opacity: 1, duration: 0.25 });
11
});
12

13
document.addEventListener("keyup", (e) => {
14
  if (
15
    e.key == "Escape" &&
16
    document.querySelector(`.modal.${IS_VISIBLE_CLASS}`)
17
  ) {
18
    closeModal.click();
19
  }
20
});

Alternative Implementation (method 2)

An alternative and more dynamic way is to create just one timeline for both actions and let GSAP handle the reverse logic via its reverse() method. 

Here’s the related demo for that:

Conclusion

Done, folks! With these simple steps and the help of the powerful GSAP JavaScript animation library, we developed a beautiful button-to-modal animation that catches the visitors’ eyes and brings a unique UX experience to our site. Hopefully, you love it as much as I do and will embed it in a web project.

Before closing, let’s recall our original animation:

Lastly, don’t forget to browse the Tuts+ library for more CSS and JavaScript animation tutorials.

As always, thanks a lot for reading!



Source link