DEV Community

Cover image for 10. CSS animation
Rustam Apay
Rustam Apay

Posted on

10. CSS animation

Color

We are making the app for children first. Let's make the active key appearance more attractive, to get better educational effect.

In styles.css create pulse animation. And replace background-color with it in .key.active.

styles.css

.key.active {
    /* background-color: red; */
    animation: pulse 1s;
    position: relative;
}

@keyframes pulse {
    0% {
        background-color: black;
    }
    100% {
        background-color: red;
    }
}
Enter fullscreen mode Exit fullscreen mode

Result

Image description

Now background-color changes smoothly. @keyframes set how to change style property over time. In our case: from black to red in 1 second.

You can try to add to @keyframes also size change (width, height).

@keyframes pulse {
    0% {
        background-color: black;
        width: 100%;
        height: 100%;
    }
    100% {
        width: 150%;
        height: 150%;
        background-color: red;
    }
}
Enter fullscreen mode Exit fullscreen mode

And you will see, that it doesn't work. That's because Keys are displayed inside flex container.

Conditional rendering v-if

To achieve more freedom with active key resize animation, we need a new independent element over the old active key. We will display it only when key is active.

To show one element over another, the first one should have a style position: relative and the second position: absolute.

styles.css

.key {
  ... position: relative;
}

.key.active {
  animation: pulse 1s;
  position: absolute;
  z-index: 2;
}
Enter fullscreen mode Exit fullscreen mode

z-index:2 means that element will be displayed over elements with z-index:1 (default).

Add a conditional rendered element (active key) to Key template.

Key.js template

<div
    :class="[
                'key', 
                keyContent.code, 
                { shiftKeyPressed: isShift && shiftKey && !isActive }
            ]"
    @click="keyClick(keyContent)"
>
    <!-- add: -->
    <div v-if="isActive" :class="['key', 'active', keyContent.code]">
        <div>{{main}}</div>
        <div>{{shifted}}</div>
    </div>
    <div class="main">{{main}}</div>
    <div class="shifted">{{shifted}}</div>
</div>
Enter fullscreen mode Exit fullscreen mode

Result

Image description

Additional keyframe (0% 30% 100%)

Now animated resize works. But it is too slow. Let's make resizing 3 times faster, and color pulse leave as it is. We need an additional keyframe for that.

styles.css

@keyframes pulse {
    0% {
        background-color: black;
        width: 100%;
        height: 100%;
    }
    /* add: */
    30% {
        width: 150%;
        height: 150%;
    }
    100% {
        background-color: red;
        width: 150%;
        height: 150%;
    }
}
Enter fullscreen mode Exit fullscreen mode

Result

Image description

Now resize happens in 30% of 1 sec, and color pulsation in 100% of 1 sec.

Animated resize (transform)

Instead of width/height changing, lets we use another CSS prop transform.

styles.css

.key.active {
    animation: pulse 1s;
    /* position (4 lines) : */
    position: absolute;
    top: 0;
    left: 0;
    z-index: 2;

    width: 100%;
    height: 100%;

    /* to compensate .key style: */
    padding: -0.5rem;
    margin: -0.2rem;

    /* to center content vertically and horizontally: */
    display: flex;
    align-items: center;
    justify-content: center;

    transform-origin: center;
}

@keyframes pulse {
    0% {
        background-color: black;
        transform: scale(100%);
    }
    30% {
        transform: scale(130%);
    }
    80% {
        transform: scale(130%);
    }
    100% {
        background-color: red;
        transform: scale(100%);
    }
}
Enter fullscreen mode Exit fullscreen mode

Result

Image description

Now it looks better, isn't it?

The value of the pressed key

When key contains 2 values: main and shifted we don't want to activate both of them. Because we will sound each of them separately.

Let's create a new computed value, that returns only 1 value for active key:

Key.js computed

value() {
    const { main, shifted, code } = this.keyContent
    return (this.shiftKey ? shifted : main) || code
}

Enter fullscreen mode Exit fullscreen mode

If shiftKey is true value is shifted, otherwise value is main. If value doesn't exist we return code.

Replace with this value main in shifted in the template:

Key.js template

<div v-if="isActive" :class="['key', 'active', keyContent.code]">
    <div>{{value}}</div>
</div>
Enter fullscreen mode Exit fullscreen mode

Result

Image description

Now we see only 1 value in the active box, which is correct. This is especially important since we want to sound all keyboard symbols.

Diffs in code 10

Entire code after the chapter

Top comments (0)