DEV Community

Cover image for Create a JavaScript library. CSS animation support
Alex Shulaev
Alex Shulaev

Posted on

Create a JavaScript library. CSS animation support

As you can see, the current implementation of the library implies changing the display property from none to block. The only problem with this approach is that this property cannot be animated via CSS, which is why the modal window opens too sharply. Today we are implementing support for CSS animations when opening/closing a window.

CSS animation

Animations help improve the perception of your content and make your project truly unique.

There are several ways to implement animations, including JavaScript and CSS. CSS animations are now a very powerful tool and the main plus of such animations in performance and optimization at the browser level.

Let's take a closer look at how it works.

Keyframes

keyframes are used to specify animation property values ​​at various points in the animation. Keyframes determine the behavior of one animation loop. Animation can be repeated zero or more times.

The basic syntax looks like this:

@keyframes animationName {
  from {
    /* code here*/
  }

  to {
    /* code here*/
  }
}

In this syntax, we have a description of the animation in two states. There is also a more flexible syntax if your animation is more complex and cannot be described only by the initial and final state

@keyframes animationName {
  0% {
    /* code here*/
  }

  100% {
    /* code here*/
  }
}

Usage example:

CSS Animation Properties

The property that was used in the example animation: shade .5s alternate infinite ease; it is a short-hand which can consist of 8 separate properties.

animation-name

This is the name of the keyframe specified by @keyframes rule.

animation-name: none;
animation-name: rebound;
animation-name: rebound-slow;
animation-name: reboundFast;

animation-duration

This property determines the duration of one animation cycle. Set in seconds with s or milliseconds with ms. If an element has more than one animation specified, then you can set a different time for each, listing the values ​​separated by commas.

animation-duration: 1s;
animation-duration: 200ms;
animation-duration: .25s, 2s;

animation-timing-function

This property describes how an animation will develop between each pair of keyframes.

The property accepts the following value:

  • linear
  • ease
  • ease-in
  • ease-out
  • ease-in-out
  • cubic-bezier
  • step-start
  • step-end
  • steps
animation-timing-function: linear;
animation-timing-function: ease;
animation-timing-function: cubic-bezier(.2, .5, .3, .9);
animation-timing-function: steps(3, end);

animation-delay

This property is determined when the animation begins. Set in seconds with s or milliseconds with ms.

animation-delay: .25s;
animation-delay: 1s, 100ms;

animation-iteration-count

This property indicates how many times the animation loop is played; this is 1 by default. The value of infinite indicates that the animation will play repeat forever.

animation-iteration-count: infinite;
animation-iteration-count: 2;

animation-direction

This property indicates whether the animation should play forward, backward, or alternately forward and backward.
Available property values:

  • normal - This is the default value and the animation played as normal (forwards)
  • reverse - The animation is played backward
  • alternate - The animation reverses direction each cycle
  • alternate-reverse - The animation reverses direction each cycle, with the first iteration being played backward
animation-direction: normal;
animation-direction: reverse;
animation-direction: alternate;
animation-direction: alternate-reverse;

animation-fill-mode

This property defines how to apply styles to the animation object before and after it is executed. Available property values:

  • none - Do not apply any styles to the animated element before or after the animation is executing
  • forwards - Retain styles from the last keyframe
  • backwards - Get styles from the first keyframe and retain this style during animation-delay state
  • both - Extend animation properties in both directions forwards and backwards
animation-fill-mode: none;
animation-fill-mode: forwards;
animation-fill-mode: backwards;
animation-fill-mode: both;
animation-fill-mode: none, backwards;

animation-play-state

This property determines whether the animation will start or pause. Stopping animation inside a loop is possible using JavaScript. You can also stop the animation if the state is hover. Available property values:

  • running - The animation is currently playing. Default value
  • paused - The animation is currently paused
animation-play-state: running;
animation-play-state: paused;

Implement animation support

Now we implement animation support in the library.

Let's start by adding a new hasAnimation property. It'll take a boolean value that is false by default. In order to add an animation of the "appearance" of a modal window, we need to add a new class at the time of its opening that will contain a property that describes the animation. It seems that we can use the previously written open method. But we need this class for the duration of the animation and after the animation is complete, it should be deleted. All this logic will be written in a separate preparationOpeningModal method

/**
 * Preparing a modal window for opening
 */
preparationOpeningModal() {
    if (this.hasAnimation) {
        this.$modal?.classList.add(CLASS_NAMES.IS_OPENING);
        const handler = () => {
            this.$modal?.classList.remove(CLASS_NAMES.IS_OPENING);
            this.$modal?.removeEventListener('animationend', handler);
        };
        this.$modal?.addEventListener('animationend', handler);
    }
}

If hasAnimation is false we don't need to do anything. The animationend event is fired when a CSS animation has completed. In our case, after the modal window is opened, the class name .isOpening is added and the animationend event is subscribed. After the animation is complete, we delete the subscription and the .isOpening class name.

Styles for an opening modal window:

:root {
  --animation: cubic-bezier(0.66, 0.28, 0.09, 0.53);
}

.modal.isOpening {
  animation: fadeIn .35s var(--animation);
}

.modal.isOpening .modal__container {
  animation: downUp .35s var(--animation);
}

@keyframes downUp {
  0% {
    transform: translateY(8%);
  }

  100% {
    transform: translateY(0);
  }
}

@keyframes fadeIn {
  0% {
    opacity: 0;
  }

  100% {
    opacity: 1;
  }
}

And here is our result. A modal window that appears smoothly

Animated modal window

But closing this window is still fast, since we haven't added a separate method for this. Let's fix this

/**
 * Preparing a modal window for closing
 */
preparationClosingModal() {
    if (this.hasAnimation) {
        this.$modal?.classList.add(CLASS_NAMES.IS_CLOSING);
        const handler = () => {
            this.$modal?.classList.remove(CLASS_NAMES.IS_CLOSING);
            this.$modal?.classList.remove(this.openClass);
            this.$modal?.removeEventListener('animationend', handler);
        };
        this.$modal?.addEventListener('animationend', handler);
    } else {
        this.$modal?.classList.remove(this.openClass);
    }
}

As you can see, this is very similar to what we did in preparationOpeningModal, but there is still a significant difference. Deleting the main class should only occur after the animation is complete (if there is one), so we will transfer this part of the code from the close method to the preparationClosingModal method. For the animation when closing, we'll use the class name .isClosing.

Add styles:

.modal.isClosing {
  animation: fadeOut .35s var(--animation);
}

.modal.isClosing .modal__container {
  animation: centerUp .35s var(--animation);
}

@keyframes centerUp {
  0% {
    transform: translateY(0);
  }

  100% {
    transform: translateY(-8%);
  }
}

@keyframes fadeOut {
  0% {
    opacity: 1;
  }

  100% {
    opacity: 0;
  }
}

Now we have animation in two directions

Animated modal window


Thanks for reading! Next time we'll add a few callbacks and add a small implementation for keyboard control. Also, very soon I'll return to what I love endlessly - creating templates, and these will be ready-made templates for modal Windows that you can immediately use with the library. Subscribe, it'll be interesting! See you soon 👋

Top comments (0)