CSS Animations CSS Animations

CSS Animations: Introduction & Examples

Beginner-friendly breakdowns of various CSS animation effects, including code examples.

The most basic animated effects in CSS can be achieved through properties like transform and transition. However, the CSS Animations Level 1 working draft provides a more complex environment by utilizing animation and @keyframes properties to achieve perpetual animation effects. This is best understood through a definitive example.

Specifying animation rules using @keyframes

The @keyframes rule is used to specify the animation behavior we wish to apply to an animation identifier in the page layout. The identifier is specified through animation-name or by using the animation: name; shorthand.

@keyframes change-color {
  from {
    background-color: #fff;
  }

  to {
    background-color: #000;
  }
}

In this context, the example above will change the background-color from white to black over the duration of the animation. from refers to the beginning (0%) and to refers to the end (100%). So, the rule can also be rewritten with percentage values.

@keyframes change-color {
  0% {
    background-color: #fff;
  }

  50% {
    background-color: #f3f3f3;
  }

  100% {
    background-color: #000;
  }
}

On its own, this won’t do anything unless we specify the element we wish to animate. Furthermore, you also have to specify animation-duration since the default value is 0.

.container {
  width: 100vh;
  height: 100vh;
  animation-name: change-color;
  animation-duration: 5s;
  /* we can also rewrite this using a shorthand
	animation: change-color 5s;
*/
}

We can then call our container using a div and the outcome would be this:

keyframes example change background color

Typically, most CSS animations written in pure CSS use shorthand because it saves writing multiple lines of the animation logic. As such, here is a reference for animation property values:

animation-name: name; 
/* the name of the specific animation (to animate with @keyframes) */
animation-duration: 10s; 
/* the duration */
animation-timing-function: linear; 
/* the veolcity curve for the animation */
animation-delay: 1s; 
/* set a delay for the animation playback */
animation-iteration-count: infinite; 
/* set it to an infinite loop */
animation-direction: alternate; 
/* back and forth, use normal for default direction */
animation-fill-mode: both; 
/* direction to apply the style */
animation-play-state: paused; 
/* also accepts 'running' */

Further reading

If you would like to learn more about CSS animations in-depth, here are my recommended resources:

Examples of CSS Animations

The best way to learn anything is through examples. The following section is dedicated entirely to various effects achieved through CSS animation properties.

One last thing! Many of the example animations below have quite a bit of code associated with them; as such, I have added a max-height overflow to this article to enable a scrollbar. You can also hover over each code snippet and copy it to the clipboard to import it into your code editor.


Wave

CSS Wave Animation

The wave animation is created by first drawing an SVG path for a wave pattern and then assigning an ID to it. Afterward, we specify four nth-child classes with custom animation-delay and animation-duration variables. Each variable represents an individual wave inside the animation, and each wave can be styled independently.

The advantage of defining the pattern with SVG is that the code becomes easily reusable.

If you look at the path that we have drawn, we specify four different layers for the wave (using a custom axis) and then reference the #wave-pattern id that we set for the initial path. This is where you can also change the color appearance of each wave.

HTML

<div class="your-container">
  <svg
    class="css-waves"
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    viewBox="0 24 150 28"
    preserveAspectRatio="none"
    shape-rendering="auto"
  >
    <defs>
      <path
        id="wave-pattern"
        d="M-160 44c30 0 58-18 88-18s 58 18 88 18 58-18 88-18 58 18 88 18 v44h-352z"
      ></path>
    </defs>
    <g class="animated-waves">
      <use href="#wave-pattern" x="48" y="0" fill="rgba(155,255,255,0.7"></use>
      <use href="#wave-pattern" x="48" y="3" fill="rgba(155,255,255,0.5)"></use>
      <use href="#wave-pattern" x="48" y="5" fill="rgba(155,255,255,0.3)"></use>
      <use href="#wave-pattern" x="48" y="7" fill="rgba(155,255,255,0.3)"></use>
    </g>
  </svg>
</div>

CSS

.css-waves {
  position: relative;
  width: 100%;
  height: 15vh;
  margin-bottom: -7px; 
  min-height: 100px;
  max-height: 150px;
}

/* Here we declare the SVG node that we wish to animate. */

.animated-waves > use {
  animation: infinite-waves 25s cubic-bezier(0.55, 0.5, 0.45, 0.5) infinite;
}
.animated-waves > use:nth-child(1) {
  animation-delay: -2s;
  animation-duration: 7s;
}
.animated-waves > use:nth-child(2) {
  animation-delay: -3s;
  animation-duration: 10s;
}
.animated-waves > use:nth-child(3) {
  animation-delay: -4s;
  animation-duration: 13s;
}
.animated-waves > use:nth-child(4) {
  animation-delay: -5s;
  animation-duration: 20s;
}
@keyframes infinite-waves {
  0% {
    transform: translate3d(-90px, 0, 0);
  }
  100% {
    transform: translate3d(85px, 0, 0);
  }
}
/* Mobile Optimization */
@media (max-width: 768px) {
  .css-waves {
    height: 40px;
    min-height: 40px;
  }
}

Loading Text

CSS Loading Text Animation

This loading effect is relatively easy to implement because it uses only a handful of practical animation properties. First, you want to specify content: attr() value which you then apply to the text element you wish to animate. Afterward, you specify the animation itself, which in our case is animation: loading 5s linear infinite;.

The duration of the loading effect can be modified by changing the 5s property. And lastly, we use @keyframes to call the loading animation and change its width from 0% to 100% over that 5s period. The higher the value of animation duration, the slower the loading effect.

The specific use cases for an animation like this are transition effects for page loads, but also a reliable solution for application projects when you don’t want to rely on any libraries.

HTML

<!-- the loading-text class is specified through the content: attr(); property. change the value name to implement multiple design variations, or reuse the same class to show the loading effect in other parts of your design -->

<h2 loading-text="Loading...">Loading...</h1>

CSS

h2 {
  position: relative;
  font-size: 5em;
  color: rgb(199, 255, 110);
  text-transform: uppercase;
  border-bottom: 10px solid #ffffff;
  line-height: initial;
}

h2::before {
  content: attr(loading-text);
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  color: #b0a8e2;
  overflow: hidden;
  border-bottom: 10px solid #b0a8e2;
  animation: loading 5s linear infinite;
}

@keyframes loading {
  0% {
    width: 0;
  }

  100% {
    width: 100%;
  }
}

Text Wave

CSS Text Wave Animation

One of the first things you’ll notice about this animation is its fluidity. This is possible because we use the calc() function to mathematically calculate each transition. Since we write the animation in pure CSS we have to use multiple span elements to specify each consecutive letter in the animation.

As for modifying the depth of the wave, first, you can change the duration from 3s to a lesser or greater number. Higher means the wave effect will be slower and vice-versa. And, inside the @keyframes you can change the -24px specification to change the height of the wave.

The higher the negative value, the more pronounced the wave effect.

HTML

<div class="blwb">
     <span style="--i:1">O</span>
     <span style="--i:2">C</span>
     <span style="--i:3">E</span>
     <span style="--i:4">A</span>
     <span style="--i:5">N</span>
     <span style="--i:6">.</span>
     <span style="--i:7">.</span>
     <span style="--i:8">.</span>
     <span style="--i:9">W</span>
     <span style="--i:10">A</span>
     <span style="--i:11">V</span>
     <span style="--i:12">E</span>
     <span style="--i:13">S</span>
     <span style="--i:14">.</span>
     <span style="--i:15">.</span>
     <span style="--i:16">.</span>
</div>

CSS

.text-wave {
      margin: auto;
      display: flex;
      align-items: center;
      justify-content: center;
      position: relative;
    }

.text-wave span {
      position: relative;
      color: rgb(255, 255, 255);
      font-size: 40px;
      font-family: monospace;
      animation: wave 3s ease-in-out infinite;
      animation-delay: calc(.1s*var(--i));
    }

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

      20% {
        transform: translateY(-24px);
      }

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

Pulse / Ripple Effect

CSS Pulse Effect Animation

We start by creating a container for the circle we wish to apply the effect to. This is specific to the demo but you can reuse the code for whatever other elements on your page. After, we create a class called .circle which will serve as the animated ripple effect.

Two notable properties we use in this class are opacity: 0.5; and animation: ease-out;. The opacity is what creates the illusion of having ripples/pulse, and the ease-out transition makes those ripples ease out of the original container.

Next, we take our .circle class and apply to it the nth-of-type() property. For this example, we are using 3 individual circles which ease out of the original container. Inside nth-of-type calls, we apply animation-delay with the values of -0.5s;-1s;-1.5s. The higher the negative value the longer it will take for the effects to fully render.

And lastly, we apply @keyframes to our specified pulse animation. In this example, we utilize the transform: scale() property. This defines the size of the pulses for each animation. The higher the value, the larger the outgoing ripples are going to appear.

HTML

<div class="pulse-effect">
     <div class="circle"></div>
     <div class="circle"></div>
     <div class="circle"></div>
     <div class="circle"></div>
</div>

CSS

.pulse-effect {
      background-color: #f6efffa1;
      height: 100px;
      width: 100px;
      border-radius: 100%;
      position: relative;
      margin: auto;
}

.circle {
      position: absolute;
      background-color: inherit;
      height: 100%;
      width: 100%;
      border-radius: 100%;
      opacity: 0.5;
      animation: pulse 3s ease-out infinite;
}

.circle:nth-of-type(1) {
      animation-delay: -0.5s;
}

.circle:nth-of-type(2) {
      animation-delay: -1s;
}

.circle:nth-of-type(3) {
      animation-delay: -1.5s;
}

@keyframes pulse {
      100% {
        transform: scale(1.75);
        opacity: 0;
      }
}

Counter (Numbers)

CSS Counter Animation

The counter property is easy to overlook because typically you add numbers to certain elements by hand. However, it comes in handy when you want to do in-depth nested assignments to menu items or large documentation pages.

Additionally, you can put together an automated counter for blog post headings. E.g. You are writing a review on multiple tools. And, best of all, the counter can be styled individually giving you more design freedom.

But, for this demo – we are focusing on using the counter property to create an automated counter effect. So, let’s dig in and understand how it works. For this example, we first create a container that will contain the counter animation. You can customize this as you like. Next, we create our .count-numbers class which includes the animation syntax, in this case, it is animation: count-numbers 10s linear infinite forwards;.

To break it down, we specify the name for our animation, we set the duration to 10 seconds, and we set the animation-direction to normal because we don’t want it to count back from 10. Although, you can set it to alternate if you wish for your counter to count backward, also.

Moving on, we specify a new class called .count-numbers::before which we use to name our counter, in this case, content: counter(count);. This is important because the next step is to use the counter-name to animate the effect through @keyframes.

The last step is to write our specifications for the animation to render. In our demo, we count from 1 to 10, so we specify our @keyframes value from 0% to 100% in 10% increments. Each increment contains a counter-increment statement that also uses our counter-name: counter-increment: count 0;.

So, at 0% our increment is set to 0 and at 10% it is set to 1 to project the effect of a counter.

Also, try changing the content: counter(count); specification to content: counter(count, upper-roman); and see what happens!

HTML

<main class="counter-container">
<div class="counter-card count-numbers"></div>
</main>

CSS

.counter-container {
      display: grid;
      grid-gap: 2rem;
      grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
      margin: auto;
      max-width: 100%;
      padding: 2rem;
}

.counter-card {
      align-items: center;
      border-radius: 10px;
      display: flex;
      height: 15rem;
      justify-content: center;
      position: relative;
      width: 100%;
}

.count-numbers {
      animation: count-numbers 10s linear infinite forwards;
      background-color: #f3f3f3;
      counter-reset: count 0;
}

.count-numbers::before {
      color: #000;
      content: counter(count);
      font-size: 5rem;
}

@keyframes count-numbers {
      0% {
        counter-increment: count 0;
      }

      10% {
        counter-increment: count 1;
      }

      20% {
        counter-increment: count 2;
      }

      30% {
        counter-increment: count 3;
      }

      40% {
        counter-increment: count 4;
      }

      50% {
        counter-increment: count 5;
      }

      60% {
        counter-increment: count 6;
      }

      70% {
        counter-increment: count 7;
      }

      80% {
        counter-increment: count 8;
      }

      90% {
        counter-increment: count 9;
      }

      100% {
        counter-increment: count 10;
      }
}

Bouncing Ball

CSS Bouncing Ball Animation

We begin by first creating a container for our ball, in this case, it is .ball-container.

Next, we specify the size of the ball and style of its appearance using a combination of background colors and shadow effects. In our demo, we have gone for a more glowy effect, but you can modify this to your own needs. And finally, we specify the animation, in this case, we set a duration to 5s and also apply ease-in-out which means the transition has both a slow start and an end.

After the ball is drawn and the animation is set, we can write our @keyframes rules. To achieve the bouncing effect, we use transform: translatey(); in increments of 50%, so 0% to 50% to 100%. The emphasis is on 50% because here we set the height of the bounce by specifying transform: translatey(-50px); – the bounce/float will be 50px in height (relative to the container). The higher the negative number, the higher the ball is going to bounce.

Likewise, specifying a smaller number will reduce the size of the bounce.

The last part is to add a shadow, although you can remove this also since it will have no effect on the ball animation itself. The only difference with the shadow is that we use the transform: scale() property to resize the shadow in a 2D context. We set the values according to the scale of effect we wish to accomplish.

HTML

<div class="ball-container"></div>
<div class="ball-shadow"></div>

CSS

.ball-container {
      margin: auto;
      animation: floating 5s ease-in-out infinite;
      height: 100px;
      width: 100px;
      border-radius: 50%;
      position: relative;

      background: radial-gradient(circle at 75% 30%,
          rgb(107, 6, 6) 5px,
          rgb(36, 187, 187) 8%,
          rgb(228, 26, 26) 60%,
          rgb(173, 221, 221) 100%);
      box-shadow: inset 0 0 20px #fff, inset 10px 0 46px #d3f8c8,
        inset 88px 0px 60px #b4c3dd, inset -20px -60px 100px #5b43e7,
        inset 0 50px 140px #6bdf7e, 0 0 90px #fff;
}

@keyframes floating {
      0% {
        transform: translatey(0px);
      }

      50% {
        transform: translatey(-50px);
      }

      100% {
        transform: translatey(0px);
      }
}

.ball-shadow {
      width: 95px;
      height: 30px;
      top: 50%;
      animation: expanding 5s infinite;
      position: relative;
      border-radius: 50%;
      margin: auto;
      background: radial-gradient(circle at 75% 30%, rgb(221 215 243) 5px, rgb(36, 187, 187) 8%, rgb(228, 26, 26) 60%, rgb(173, 221, 221) 100%);
      box-shadow: inset 0 0 20px #fff, inset 10px 0 46px #3f51b500, inset 88px 0px 60px #ffffff99, inset -20px -60px 100px #5b43e791, inset 0 50px 140px #ffffff, 0 0 90px #39316b;
    }

@keyframes expanding {
      0%,
      100% {
        transform: scale(0.5);
      }

      50% {
        transform: scale(0.75);
      }
}

Coin Flip

CSS Coin Flip Animation

What I love about this animation is that we can set an incredibly precise rotation radius to achieve an effect that feels like the coin is genuinely flipping. So, to get started you will need 2 images (I am using SVG for this demo, but normal photos work just as fine. Just make sure to apply the correct class to each image.) and set them to opacity: 0;. We set it to 0 because later on, we use @keyframes to change their opacity so the images come into the view at certain positions during the animation.

The .image-container class is used to specify the dimensions for the images inside the coin. Make sure you also specify this for the actual images, as shown in the snippet below. Next, we specify .coin-style which is the outer part (the coin itself). Technically, you can set this to transparent but for the sake of a demo, we make it visible.

The main concept for the .coin-style class is the way we add the animation, which in this case is: animation: coin-flip 1.25s cubic-bezier(0.93, 0.05, 0.9, 0.71) infinite alternate;.

The point of interest is the cubic-bezier() specification, which gives us the rotating curve effect for the coin container. This is practically impossible to write on your own, so my recommendation is to use any generator tool to render the desired curve effect.

And lastly, inside our @keyframes we apply the scaleX() function to resize the coin appearance on x-axis basis. Even the most minimal change to the values provided (in this demo) will modify how the “flip” effect appears.

I think the implementation below is as close as it gets to perfect, but maybe you can do better!

HTML

<div class="coin-style">
    <div class="image-container">

        <svg class="firstimage" width="88" height="88" viewBox="0 0 32 32" data-name="Layer 1" id="Layer_1"
            xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
            <path class="cls-1"
                d="M23.5,2h-12a.47.47,0,0,0-.35.15l-5,5A.47.47,0,0,0,6,7.5v20A2.5,2.5,0,0,0,8.5,30h15A2.5,2.5,0,0,0,26,27.5V4.5A2.5,2.5,0,0,0,23.5,2Z" />
            <path class="cls-2"
                d="M11.69,2a.47.47,0,0,0-.54.11l-5,5A.47.47,0,0,0,6,7.69.5.5,0,0,0,6.5,8h3A2.5,2.5,0,0,0,12,5.5v-3A.5.5,0,0,0,11.69,2Z" />
            <path class="cls-3"
                d="M22.5,11a.5.5,0,0,0-.5.5v4.94l-.51-2.06a.52.52,0,0,0-1,0L20,16.44V11.5a.5.5,0,0,0-1,0v9a.51.51,0,0,0,.44.5.5.5,0,0,0,.55-.38l1-4.06,1,4.06a.5.5,0,0,0,.49.38h.06a.51.51,0,0,0,.44-.5v-9A.5.5,0,0,0,22.5,11Z" />
            <path class="cls-3"
                d="M11.5,11h-2a.5.5,0,0,0-.5.5v9a.5.5,0,0,0,1,0V17h1.11l.9,3.62a.51.51,0,0,0,.49.38h.12a.51.51,0,0,0,.37-.61l-.88-3.51A1.51,1.51,0,0,0,13,15.5v-3A1.5,1.5,0,0,0,11.5,11Zm.5,4.5a.5.5,0,0,1-.5.5H10V12h1.5a.5.5,0,0,1,.5.5Z" />
            <path class="cls-3"
                d="M16,11a.5.5,0,0,0-.49.42l-1.5,9a.49.49,0,0,0,.41.57.5.5,0,0,0,.57-.41L15.26,19h1.48L17,20.58a.49.49,0,0,0,.49.42h.08a.49.49,0,0,0,.41-.57l-1.5-9A.5.5,0,0,0,16,11Zm-.58,7L16,14.54,16.58,18Z" />
        </svg>

        <svg class="secondimage" width="88" height="88" viewBox="0 0 32 32" data-name="Layer 1" id="Layer_1"
            xmlns="http://www.w3.org/2000/svg">
            <defs>
                <style>
                    .cls-1 {
                        fill: #a08383;
                    }

                    .cls-2 {
                        fill: #e1ebe9;
                    }

                    .cls-3 {
                        fill: #770ba1;
                    }

                    .cls-4 {
                        fill: #0a5097;
                    }
                </style>
            </defs>
            <path class="cls-1"
                d="M23.5,2h-12a.47.47,0,0,0-.35.15l-5,5A.47.47,0,0,0,6,7.5v20A2.5,2.5,0,0,0,8.5,30h15A2.5,2.5,0,0,0,26,27.5V4.5A2.5,2.5,0,0,0,23.5,2Z" />
            <path class="cls-2" d="M15,2h7a1,1,0,0,1,0,2H15a1,1,0,0,1,0-2Z" />
            <path class="cls-2" d="M6,13.5v-2a1,1,0,0,1,2,0v2a1,1,0,0,1-2,0Z" />
            <path class="cls-2" d="M6,24.5v-8a1,1,0,0,1,2,0v8a1,1,0,0,1-2,0Z" />
            <path class="cls-4"
                d="M21.5,15.5h-1A.5.5,0,0,1,20,15V12.5a.5.5,0,0,1,.5-.5h2a.5.5,0,0,0,0-1h-2A1.5,1.5,0,0,0,19,12.5V15a1.5,1.5,0,0,0,1.5,1.5h1a.5.5,0,0,1,.5.5v2.5a.5.5,0,0,1-.5.5h-2a.5.5,0,0,0,0,1h2A1.5,1.5,0,0,0,23,19.5V17A1.5,1.5,0,0,0,21.5,15.5Z" />
            <path class="cls-4"
                d="M15.5,12h2a.5.5,0,0,0,0-1h-2A1.5,1.5,0,0,0,14,12.5V15a1.5,1.5,0,0,0,1.5,1.5h1a.5.5,0,0,1,.5.5v2.5a.5.5,0,0,1-.5.5h-2a.5.5,0,0,0,0,1h2A1.5,1.5,0,0,0,18,19.5V17a1.5,1.5,0,0,0-1.5-1.5h-1A.5.5,0,0,1,15,15V12.5A.5.5,0,0,1,15.5,12Z" />
            <path class="cls-4"
                d="M11,12a1,1,0,0,1,1,1,.5.5,0,0,0,1,0,2,2,0,0,0-4,0v6a2,2,0,0,0,4,0,.5.5,0,0,0-1,0,1,1,0,0,1-2,0V13A1,1,0,0,1,11,12Z" />
        </svg>
    </div>
</div>

CSS

svg {
      color: #151516;
      position: absolute;
    }

svg.firstimage {
      opacity: 0;
      animation: logo-flip 2.5s linear infinite alternate;
    }

svg.secondimage {
      opacity: 0;
      animation: logo-flip 2.5s linear 2.5s infinite alternate;
    }

.image-container {
      position: relative;
      height: 88px;
      width: 88px;
    }

.coin-style {
      background: rgb(233, 226, 226);
      width: 136px;
      height: 136px;
      border-radius: 100%;
      margin: 0 auto;
      display: flex;
      justify-content: center;
      align-items: center;
      box-shadow: 0px 15px 15px -19px rgb(255, 255, 255);
      animation: coin-flip 1.25s cubic-bezier(0.93, 0.05, 0.9, 0.71) infinite alternate;
}

@keyframes coin-flip {
      0% {
        transform: scaleX(0.95);
      }

      100% {
        transform: scaleX(0.08);
        border-radius: 50%;
      }
    }

@keyframes logo-flip {
      0% {
        opacity: 0;
      }

      50% {
        opacity: 0;
      }

      53% {
        opacity: 1;
      }

      100% {
        opacity: 1;
      }
}

Slide-In

CSS Slide-In Animation

To make this animation work, we use the animation: ease-out; function in combination with a negative position value inside @keyframes. So, in this example we specify 0% {opacity: 0;left: -700px;} which makes our slide-in element invisible at the beginning, but also positioned 700px outside the container.

Afterward, we specify 100% {opacity: 1;left: 0;} which by the time our animation is over (we have it set to 2 seconds) will return normal visibility, and position our element back to its relative position.

An interesting thing to note is that this effect works in all directions.

If you want to change the slide-in effect to appear from the right side, you need to change the left:; values to right:; and vice-versa for positions like top and bottom. You can also delay the animation by adjusting how long it takes for the element to slide-in.

A higher value will slow the animation down.

HTML

<h2 id="slide-in" class="animation">
                Slide-In Animation
</h2>

CSS

.animation {
      position: relative;
      animation: animation 2s ease-out;
    }

#slide-in {
      text-align: center;
      color: #fff;
    }

@keyframes animation {
      0% {
        opacity: 0;
        left: -700px;
      }

      100% {
        opacity: 1;
        left: 0;
      }
    }

Blob Effect

CSS Blob Border Animation

First of all, what the heck is a Blob? As Ian Latchmansingh put it, “The Blob is an amorphous, pseudo-organic shape that’s commonly used to anchor landing pages visually. It usually serves as a mask or backdrop for an illustration. About 90% of the time the Blob is filled with a gradient and sits on the lowest layer of a design.”. It certainly is one of the more common patterns in modern web design. But, how do we animate it?

We start by creating a blob-effect container and also specify 3 individual span elements inside the container. We do this because we actually “draw” the blob ourselves using a combination of border and border-radius properties.

To achieve the varied effect, we use nth-child to style each element individually. If you want to get funky with it, feel free to change the percentage properties to adjust the blob appearance.

The animation itself is achieved by using transform: rotate() property inside a @keyframes specification. We set it to 0 to 360 degrees because this gives us a perpetual effect. The color overlay is done through :hover and lets us set a custom background color. And, additionally, we also create a separate container inside the blob itself. This gives you the ability to style individual parts of your page layout to have this specific animation effect.

HTML

<div class="blob-effect">
     <span></span>
     <span></span>
     <span></span>
<div class="div-container">
      <a href="#">Hover</a>
</div>
</div>

CSS

.blob-effect {
  position: relative;
  width: 200px;
  height: 200px;
  display: flex;
  justify-content: center;
  align-items: center;
}

.blob-effect span:nth-child(1) {
  position: absolute;
  top: 0px;
  left: 0px;
  width: 100%;
  height: 100%;
  border: 2px solid #a9ff68;
  border-radius: 38% 62% 63% 37% / 41% 44% 56% 59%;
  transition: 0.5s;
  animation: rotate-blob 5s linear infinite;
}

.blob-effect:hover span:nth-child(1) {
  background: #d76bb1;
  border: none;
}

.blob-effect span:nth-child(2) {
  position: absolute;
  top: 0px;
  left: 0px;
  width: 100%;
  height: 100%;
  border: 2px solid #a9ff68;
  border-radius: 38% 62% 63% 37% / 41% 44% 56% 59%;
  transition: 0.5s;
  animation: rotate-blob 4s linear infinite;
}

.blob-effect:hover span:nth-child(2) {
  background: #f192d0;
  border: none;
}

.blob-effect span:nth-child(3) {
  position: absolute;
  top: 0px;
  left: 0px;
  width: 100%;
  height: 100%;
  border: 2px solid #a9ff68;
  border-radius: 38% 62% 63% 37% / 41% 44% 56% 59%;
  transition: 0.5s;
  animation: rotate-blob2 10s linear infinite;
}

.blob-effect:hover span:nth-child(3) {
  background: #f06ec294;
  border: none;
}

@keyframes rotate-blob {
  0% {
    transform: rotate(0deg);
  }

  100% {
    transform: rotate(360deg);
  }
}

@keyframes rotate-blob2 {
  0% {
    transform: rotate(360deg);
  }

  100% {
    transform: rotate(0deg);
  }
}

.div-container {
  position: relative;
  padding: 40px 60px;
  color: #fff;
  text-align: center;
  transition: 0.5s;
  z-index: 10000;
}

.div-container p {
  color: #fff;
}

.div-container a {
  position: relative;
  display: inline-block;
  margin-top: 10px;
  border: 2px solid #fff;
  padding: 6px 18px;
  text-decoration: none;
  color: #fff;
  font-weight: 600;
  border-radius: 73% 27% 44% 56% / 49% 44% 56% 51%;
}

.div-container a:hover {
  background: #fff;
  color: #333;
}

Text Switch

CSS Text Switch Animation

Animation effects are typically reserved for creative web designs. And in this case, this text switch effect will help to create a strong first impression for your site visitors. Ideal for header introductions, or if customized – can be used to showcase product features, etc.

The first thing we do is create a container for the actual effect. After, we specify a new div class that is going to contain the animation logic. In our case, we use an 8s animation length, combined with 3 separate animation-delay specifications.

The delay is used to determine when a specific word is going to come into the view after we add our @keyframes logic.

HTML

<div class="g-container">
<div class="word">Text</div>
<div class="word">Switch</div>
<div class="word">Animation</div>
</div>

CSS

.g-container {
      position: relative;
      font-family: monospace;
      color: rgb(255, 255, 255);
      font-size: 4em;
      filter: contrast(15);
}

.word {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    animation: switch 8s infinite ease-in-out;
    min-width: 100%;
    margin: auto;
}

.word:nth-child(1) {
      animation-delay: -7s;
}

.word:nth-child(2) {
      animation-delay: -6s;
}

.word:nth-child(3) {
      animation-delay: -5s;
}

@keyframes switch {

      0%,
      5%,
      100% {
        filter: blur(0px);
        opacity: 1;
      }

      50%,
      80% {
        filter: blur(180px);
        opacity: 0;
      }
}

Hover Highlight

CSS Hover Highlight Animation

Admittedly, this specific effect does not use concrete animation properties. However, the usage of attr() and the var() function should be inspiring enough to try and further customize this effect.

If you look at the ul li a::before specification – we use attr() to specify which element we wish to attribute the effect to. Additionally, we add a variable called –clr which you use to set a custom color for each item you wish to apply the hover effect.

For this example, we have also added border-right property to indicate which color we use for each of the elements. You can remove it and the effect will still work.

HTML

<ul>
<li style="--clr:#a4e935">
<a href="#" hover-text=" Hover"> Hover </a>
</li>
<li style="--clr:#61cbb7">
<a href="#" hover-text=" Highlight"> Highlight </a>
</li>
</ul>

CSS

ul {
  position: relative;
  display: flex;
  flex-direction: inherit;
  gap: 25px;
}
ul li {
  position: relative;
  list-style: none;
}
ul li a {
  font-size: 2em;
  font-family: monospace;
  text-decoration: none !important;
  letter-spacing: 0px;
  line-height: 1em;
  color: rgb(255, 255, 255);
  
}
ul li a::before {
  content: attr(hover-text);
  position: absolute;
  color: var(--clr);
  width: 0;
  overflow: hidden;
  transition: 1s;
  border-right: 8px solid var(--clr);
  -webkit-text-stroke: 1px var(--clr);
}
ul li a:hover::before {
  width: 100%;
  filter: drop-shadow(0 0 25px var(--clr))
}