Yashasvi Singh
aUnicornDev's Blog

aUnicornDev's Blog

TabsMonster CSS Art (with :hover and @keyframe animation)

TabsMonster CSS Art (with :hover and @keyframe animation)

Yashasvi Singh's photo
Yashasvi Singh
·Jan 19, 2022·

7 min read

Featured on Hashnode

Table of contents

In this article, we will be looking at building a CSS Art with animations(BONUS)

Creating the Static monster

Before we begin let us look at the relative positioning unit used in this article -

Using rem in CSS

rem is equal to the computed value of font-size on the root element. When specified on the font-size property of the root element, the rem units refer to the property’s initial value.

This means that 1rem equals the font size of the HTML element (which for most browsers has a default value of 16px).

But using multiples of 16px will not be convenient, so we change the root size(font-size of html) to 10px by setting font-size :62.5%;

html {
  font-size: 62.5%;
}

After this, all sizes will be relative to 10px.. 25rem would be 250px and so on....

Dividing the Art into Layers

We need to divide and make the following Layers with HTML and CSS and wrap them in a single HTML element.

Layers in the CSS Art

<div class="logo">

  <div class="monster__body">
<!--     Layer 1 -->
    <div class="monster__circle">
    </div>


<!--   Layer 2   -->
    <div class="monster__rectangle">    
    </div>
<!--   Layer 3  -->
    <div class = "eye-ball-space">
    </div>

  </div>

</div>

the logo is used to provide the background color and center everything whereas the .monster__body is just a wrapper class in which the layers will exist with a position: relative property.

.logo {
  width: 100%;
  height: 40rem;
  background-color: #5CDB94;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}

.monster__body {
  position: relative;
  height: 26.5rem; 
  width: 25rem;
  border-radius:12.5rem 12.5rem 0 0;

}

Layer 1

Looking at Layer 1, it looks like we need two semi circles of two different colors joined together.

Had it been a simple circle with a color, it would have been easier to make.

That's the NEAT part, there is only one circle , just the background color is divided into two.

Let's see how that happens..

.monster__circle {
  width: 25rem;
  height: 25rem;
  border-radius: 50%;
  position: absolute;
  z-index: 1;
  background-color: #389583;
}

This CSS style will create a circle, but for single color.

Instead of background-color property, we need the background be set to a linear gradient.

Something like

background: linear-gradient(#389583 50%, #8DE4AF 50%);

What this will do is divide the first 50% of the background into the color #389583 and the next 50% in the color #8DE4AF .

And voila, your circle which looks like two semi-circles will be ready..

Layer 1 using linear Gradient

But WAIT!!!

Don't we need the semi-circles divided vertically instead of horizontally??

For that, just rotate the linear-gradient to a 90deg,

background: linear-gradient(90deg, #389583 50%, #8DE4AF 50%);

Layer 2

As you would have guessed by now, the rectangle will also have a similar background as for Layer 1

.monster__rectangle {
  width: 25rem;
  height: 14rem;
  position: absolute;
  bottom:0;
  z-index: 2;
  background: linear-gradient(90deg, #389583 50%, #8DE4AF 50%);
}

As soon as you add this class, an inverted monster body will be visible..

Initial position for Layer 2

This happens because if in position:relative , if no value for top and left are provided, the default is taken as 0 .

Here, both the circle element and the rectangle will have position as left :0 ; , top:0;.

If we push the rectangle to the bottom, we will get our desired result.

Adding bottom as zero, we can position the .monster__rectangle relative to the .monster__body .. i.e touching the bottom.

bottom:0;

Layer 3

The third layer is just a transparent square with border-radius of 50% and a solid border of blue color.

.eye-ball-space {
  position: absolute;
  z-index: 3;
  width: 7rem;
  height: 7rem;
  border-radius: 50%;
  background-color: transparent;
  border: 16px solid #05396B;
  top: 15%;
  left: 50%;
  transform: translateX(-50%);
  overflow: hidden;
}

Here the top: 15%;left: 50%; will position the Layer 3 as shown in Fig 1 and the transform: translateX(-50%) will move the Layer 3 as shown in Fig 2.

Translate property at work

Creating the Eye Balls

<!--   Layer 3  -->
    <div class = "eye-ball-space">
        <div class = "eye-ball">
          <div class="inner-eye-ball">
          </div>
      </div>
    </div>

Here the eye-ball and inner-eye-ball are squares of appropriate sizes with a border radius of 50%.

They set to absolute position with trial and error.

There is no significance of the position of both unless animations are involved(they are involved later in this article)

.eye-ball {
  position: absolute;
  top: 60%;
  left: 65%;

  transform: translate(-50%, -50%);
  background-color: #05396B;
  border-radius: 50%;
  height: 40px;
  width: 40px;
  overflow: hidden;
  z-index: -1;
}

.inner-eye-ball {
  position: absolute;
  height: 16px;
  width: 16px;
  background-color: white;
  border-radius: 50%;
  top: 20%;
  left: 40%;
}

Creating the Mouth and Teeth

<!--   Layer 2   -->
    <div class="monster__rectangle">   
       <div class="monster__mouth">
        <div class="monster__teeth"></div>
        <div class="monster__teeth"></div>
        <div class="monster__teeth"></div>

      </div>
    </div>

The monster__mouth is a rectangle with curved corners positioned centrally in the monster__rectangle .

.monster__mouth {
  width: 16.5rem;
  height: 4rem;
  border-radius: 2rem;
  background-color: #05396B;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  overflow: hidden;
}

.monster__teeth {
  margin-top: 1px;
  width: 2rem;
  height: 2rem;
  background-color: white;
  clip-path: polygon(0 0, 50% 75%, 100% 0)

}

.monster__teeth:first-child {
  margin-left: 2rem;
}

As for the .monster__teeth , these triangles are made using the clip-path property set to polygon which will be the coordinates in a square. (The blue square is just given for reference.)

The clip path property for a triangle

The .monster__teeth:first-child property selects the first teeth and gives it a margin of 2rem.

All other teeth remain stacked to each other(because of display:flex of the parent .monster__mouth ).

BONUS : Adding Animations

For the animation that we are going to add, we will need to update a few properties in the previously added classes. Please make the changes/replace code of all the classes shown in the code snippets below.

Adding @keyframes to eyes

According to MDN Web Docs

The @keyframes CSS at-rule controls the intermediate steps in a CSS animation sequence by defining styles for keyframes (or waypoints) along the animation sequence. This gives more control over the intermediate steps of the animation sequence than transitions.

@keyframes roll-inner {
  0% {
    left: 30%;
  }
  33% {
    left: 0%;
  }
  66% {
    left: 60%;
  }
  100% {
    left: 30%;
  }
}

@keyframes roll {
  0% {
    left: 23%;
  }
  33% {
    left: 0%;
  }
  66% {
    left: 45%;
  }
  100% {
    left: 23%;
  }
}

In the above code, we have created two keyframes, one for the inner eye and one for the eye.

The @keyframe animation is divided into three equal parts, starting from 0%and ending at 100% , with the position of the eye and inner-eye visualized in the image below.

keyframe animations visualized

Now we just add the animation property to the respective keyframe name, with a time period of 3s and set to infinite.

.eye-ball {
  position: absolute;
  top: 23%;
  left: 23%;
  background-color: #05396B;
  border-radius: 50%;
  height: 40px;
  width: 40px;
  overflow: hidden;
  z-index: -1;
  animation:roll 3s infinite;
}

.inner-eye-ball {
  position: absolute;
  height: 16px;
  width: 16px;
  background-color: white;
  border-radius: 50%;
  top: 30%;
  left: 30%;
  animation:roll-inner 3s infinite;
}

Adding :hover Animation on Teeth

.monster__teeth {
  margin-top: 1px;
  width: 2rem;
  height: 2rem;
  background-color: white;
  clip-path: polygon(0 0, 50% 75%, 100% 0);
  transition: 0.4s;
}
.monster__body:hover .monster__teeth{
  transform: translateY(-60%);
  transition:.4s;
}

Whenever we hover over .monster__body , two things will happen

  • .monster__teeth will move in the upward direction because of the translateY(-60%) property.
  • transition:.4s will smoothen the movement instead of sudden displacement.

Final Animation at Work

There is one small issue though 😟

If we apply border to the .monster__body class , we can see that we have extra area that comes under the monster body.

And when we hover in this area, the .monster-teeth transition would still take place.

Extra Space Issue

To fix that ,we will simply add border-radius to the .monster__body class.

.monster__body {
  position: relative;
  height: 26.5rem; 
  width: 25rem;
  border-radius:12.5rem 12.5rem 0 0;
  border:1px solid black;
  /*border used for demo purpose*/
}

Extra Space Issue resolved

Now the hover will work as expected !! You can hover over and check that here below!

Conclusion

This concludes the tabsMonster mascot Art with CSS Animations.

Wouldn't adding JS Animations make it more awesome???.

I did add some JS animations in the final version, you can check it out here.

In case you have any doubts or suggestions regarding the article(s), feel free to contact me on my email or on Twitter at @aUnicornDev.

The CSS Art built in this articles used in the tabsMonster project. Everyone is more than welcome to checkout and contribute in this Open Source Project.

Thanks for Reading 😊

Did you find this article valuable?

Support Yashasvi Singh by becoming a sponsor. Any amount is appreciated!

Learn more about Hashnode Sponsors
 
Share this