Day 2— 100 Days CSS Challenge

Hemant Kumar
Implement Web Design
5 min readDec 6, 2019

I’ve gone for a lot of hackathons as a full stack developer, and one of my main difficulties was implementing the designer’s mockups on the website. Apart from the obvious placement-related issues, responsivity on different device screen sizes, etc., the main problem any front-end web designer faces is making CSS Animations.

A simple loading animation made with CSS Animations

CSS animations are incredibly simple to make, and I thought I could share my expertise in the same by implementing a few simple designs and animations through the course of this blog series.

A big shoutout to Matthias Martin who created the https://100dayscss.com/ series, where he puts up a new CSS Animation everyday and challenges you to implement it. I urge aspiring front-end developers of all skill levels to give the challenge a go, you will always learn something new!

So, for this article, I have picked up the https://100dayscss.com/?dayIndex=1 challenge, and explained its implementation step-by-step.

Day 2 CSS Challenge

Approaching the Challenge

In any CSS Animation, try to break up the animation into smaller, modular pieces. In this particular case, we can see three different cases: -

  1. Placing and styling the three horizontal lines
  2. Performing the first animation, i.e., converting the three horizontal lines to the cross mark
  3. Performing the reverse animation, i.e., converting the cross mark back to the three horizontal lines.

Let’s get cracking!

Setting up the static components and placing them before adding animations

First we begin with the blank slate that the challenge provides us with, and make the three horizontal lines sans any animations.

<div class="frame">
<div class="icon">
<div class="line-1"></div>
<div class="line-2"></div>
<div class="line-3"></div>
</div>
</div>

I have used CSS variables to make the code less cluttered. Note that the animation property has not yet been added to the line classes.

/* Declaring CSS Variables*/
:root {
--margin-between-lines: 20px;
--animation-delay:1s;
--hamburger-line-thickness:4px;
}
.icon {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
cursor: pointer;
}
.line-1{
position : relative;
width : 5em;
border : var(--hamburger-line-thickness) solid white;
background-color: white;
border-radius:10px;
}
.line-2{
margin : var(--margin-between-lines) 0 0 0;
width : 5em;
border : var(--hamburger-line-thickness) solid white;
border-radius:10px;
background-color: white;
}
.line-3{
margin : var(--margin-between-lines) 0 0 0;
width : 5em;
border : var(--hamburger-line-thickness) solid white;
border-radius:10px;
background-color: white;
}
Result after Step 1

Implementing the first animation

While implementing any animation, it is important to split up the animation into multiple keyframes. In this particular case, we need to convert the three horizontal lines into the cross mark. While breaking this down into keyframes, we notice that: -

  1. The middle line disappears.
@keyframes animate-line-2 {
0% {
transform: scale(1);
opacity: 1;
}
100% {
opacity:0;
}
}

2. The top line moves down to the same position as the middle line, and then rotates 45 degrees.

@keyframes animate-line-1 {
0% {
opacity: 1;
}
50% {
transform: translate3d(0,calc(var(--margin-between-lines) + var(--hamburger-line-thickness)*2),0);
}
100% {
transform: translate3d(0,calc(var(--margin-between-lines) + var(--hamburger-line-thickness)*2),0) rotate(45deg);
}
}

3. The bottom line moves up to the same position as the middle line, and then rotates -45 degrees.

@keyframes animate-line-3 {
0% {
opacity: 1;
}
50% {
transform: translate3d(0,calc((var(--margin-between-lines) + var(--hamburger-line-thickness)*2)*(-1)),0);
}
100% {
transform: translate3d(0,calc((var(--margin-between-lines) + var(--hamburger-line-thickness)*2)*(-1)),0) rotate(-45deg);
}
}

To demonstrate the first animation, let’s add a class animate-line to each of the horizontal lines that is toggled when the icon is clicked. So, if the class is present, then the first animation is triggered. When it is not present, the result from step 1 is automatically loaded.

.line-1.animate-line{
animation : animate-line-1 var(--animation-delay);
animation-fill-mode: forwards;
}
.line-2.animate-line{
animation : animate-line-2 var(--animation-delay);
animation-fill-mode: forwards;
}
.line-3.animate-line{
animation : animate-line-3 var(--animation-delay);
animation-fill-mode: forwards;
}

The JQuery code of an onclick listener toggling the animate-line class.

$(document).on("click", ".icon", function(){
$(this).find("div").toggleClass("animate-line");
});
Result after Step 2

Implementing the Second Animation (Reverse)

For the second animation, we need to convert the cross mark back to the horizontal lines. Again, by decomposing the action into multiple keyframes, we get: -

  1. The middle line reappears.
@keyframes animate-line-2-rev {
0% {
opacity:0;
transform: scale(1);
}
100% {
opacity:1;
}
}

2. The top line is formed by the 45 degree inclined line rotating by -45 degrees, and then moving up.

@keyframes animate-line-1-rev {
0% {
transform: translate3d(0,calc(var(--margin-between-lines) + var(--hamburger-line-thickness)*2),0) rotate(-45deg);
}
50% {
transform: translate3d(0,calc(var(--margin-between-lines) + var(--hamburger-line-thickness)*2),0) rotate(0deg);
}
100% {
transform: translate3d(0,0,0);
}
}

3. The bottom line is formed by the other inclined line rotating by 45 degrees, and then moving down.

@keyframes animate-line-3-rev {
0% {
transform: translate3d(0,calc((var(--margin-between-lines) + var(--hamburger-line-thickness)*2)*(-1)),0) rotate(45deg);
}
50% {
transform: translate3d(0,calc((var(--margin-between-lines) + var(--hamburger-line-thickness)*2)*(-1)),0) rotate(0deg);
}
100% {
transform: translate3d(0,0,0);
}
}

Now, to implement this, we are placing these keyframes as the primary keyframes for the three lines initially.

.line-1{
position : relative;
width : 5em;
border : var(--hamburger-line-thickness) solid white;
background-color: white;
border-radius:10px;
animation: animate-line-1-rev var(--animation-delay);
}
.line-2{
margin : var(--margin-between-lines) 0 0 0;
width : 5em;
border : var(--hamburger-line-thickness) solid white;
border-radius:10px;
background-color: white;
animation: animate-line-2-rev var(--animation-delay);
}
.line-3{
margin : var(--margin-between-lines) 0 0 0;
width : 5em;
border : var(--hamburger-line-thickness) solid white;
border-radius:10px;
background-color: white;
animation: animate-line-3-rev var(--animation-delay);
}

Also, to ensure that before the first click this animation is not triggered, each line is initialised with class no-animate.

<div class="line-1 no-animate"></div>
<div class="line-2 no-animate"></div>
<div class="line-3 no-animate"></div>

The following CSS code is added to ensure that the animation is not triggered while the class is present.

.no-animate{
animation: none !important;
}

Finally, the onclick listener is amended to remove the no-animate class after the first click.

$(document).on("click", ".icon", function(){
$(this).find("div").toggleClass("animate-line");
$(this).find("div").removeClass("no-animate");
});

Final Result

You can view the final result as follows on CodePen.

Final Result on Codepen

--

--

Hemant Kumar
Implement Web Design

Data Science Intern at Zoox (Amazon Self-Driving); ex-SDE 2 at JP Morgan Chase — Microsoft Imagine Cup Asia Finalist