During these crazy times, of the Coronavirus pandemic, we, the web developers of the world, spend almost all-day at home. On one of those weekends, when I got bored, I decided to create a new inspiration game, which is built only with CSS and HTML. In this article, I will teach you how I created the CSS Creature of this game.

The full CodePen of my Pure CSS Game — “Coronavirus Invaders”.

Thinking of an Idea and Getting Inspiration

We are living during the Coronavirus pandemic, therefore I thought it would be a great idea to create a game in which we need to fight the virus.

I don’t know why, but I saw a CodePen of creatures created with JS and Canvas and these creatures reminded me of the way the Coronavirus is illustrated.

The second thought I had, is to create an arcade game, and again I had the thinking of the old game “Chicken Invaders”. These two thoughts were the backbone of the game I created.

The CodePen Example & Chicken Invaders Inspirations

Creating the Coronavirus Character

I was looking at the cute small creature CodePen and started to develop my Coronavirus creatures. In the end, I only used the eye structure from that example, but for me, as I have less experience in creating CSS creatures, it was beneficial.

inspiration VS my creature

Structuring the HTML of a Coronavirus Character

I was mindful throughout the creation process of this project. During any of the steps, if I felt uneasy about something- I stopped the process and began planning again in order to get a better result.

When it comes to HTML, I always try to create semantic names and structures. This way it is easy for me to understand the code I have written.

Coronavirus creatures HTML:

<label class="corona-virus">
  <div class="scalp">
    <span class="hair1"></span>
    <span class="hair2"></span>
    <span class="hair3"></span>
    <span class="hair4"></span>
    <span class="hair5"></span> 
    <span class="hair6"></span>
    <span class="hair7"></span>
    <span class="hair8"></span>
    <span class="hair9"></span>
    <span class="hair10"></span>
    <span class="hair11"></span>
    <span class="hair12"></span>
  </div>
  <div class="eye1"></div>
  <div class="eye2"></div>
  <input type="radio"></input>
</label>

You may ask why am I using the wrapper element with HTML element of <label>, and what is the usage of the <input type=”radio”> at the end of the HTML Coronavirus? These are part of the way to create points in my new game, and we will talk about them in my next article.

Structuring & Drawing the CSS of the Coronavirus Character

The idea of creating, specifically the Coronavirus character and CSS in general, is that it is always smart to build from outside to inside because it makes us work in a more organized way.

Starting with the body
I first started drawing the body element (.corona-virus), with the same width and height, and made it circle with the border-radius property with the value of 50%, and color it with background-color: #000 (black).

In order to allow me the option to position all the other parts, like the eyes and hair, in proportion to the body, I added: position: relative.

.corona-virus{
  position: relative;
  display: block;
  width: 100px;
  height: 100px;
  border-radius: 50%;
  background-color:#000;
}

Current result:

Circle Head

Creating the eyes

I already created those two logical HTML elements for the eyes,<div class=”eye1"></div> <div class=”eye2"></div>. To select both of the eyes via one selector, I used the attribute star selector, [class*=”eye”], this way I can select both of them without the need to create another linking class name.

At this point, I’ll give them width & height in rectangle shape, color them in white with background-color: #fff. To create the egg shape I used border-radius: 50%.

To position the eyes in the correct place, I used position: absolute, the same top for both of them, and different right and left for each eye. For the last small touch, I will rotate each one of them inside with the transform property, to give them a cute look.

/* Target both eyes */
[class*="eye"]{
  position: absolute; 
  top: 25%;
  width: 20px; 
  height: 26px; 
  border-radius: 50%;
  background-color: #fff;
}
.eye1{
  left: 25%; 
  transform: rotateZ(15deg);
}
.eye2{
  right:25%; 
  transform: rotateZ(-15deg);
}

Current result:

Head with empty eyes

I created the inner part of the eye using the pseudo-element ::before, and I nested it inside the selector of both eyes (capability with Sass), which we already have ([class*=”eye”]). I positioned them with position: absolute, and because it is a pseudo-element of the eye HTML element, which we already have position: absolute, their position will be according to the white of the eyes. See the example:

[class*="eye"]{
  &::before{ 
     content: "";
     position: absolute;
     top: 50%;
     display: block;
     width: 8px;
     height: 8px;
     background-color: #000; 
     border-radius: 50%;
  }
}

Current result:

Head with full eyes

Creating the Corona “Hair”

For every hair, I created an element which represents it, for example <span class=”hair1">. I used the pseudo-elements, ::before::after, to draw them with two squares, one to create the Root of hair, and the second to create the crown on every hair. And for the crown to be in a circle shape, I added border-radius: 50%.

For all the hair, I gave position: absolute and centered them on the main body of the virus. To move the hair in a circle shape, I used the transform property with two values: First value, rotateZ, and every hair with a jumping value of 30 degrees. For example, rotateZ(0deg) rotateZ(30deg) rotateZ(60deg) and so on.

Besides that, I added a small negative margin to center every hair according to its actual size. It can also be done with transform, but I preferred not to give to many values to the transform because it becomes unreadable.

To determine the position of every hair on the scalp of the virus, I gave them all the same value of transalteY(-65px). And because the value of rotateZ is different in every hair, every hair will be positioned in a different place.

Note: In the values of transform property, the order matters! For example:
transform: rotateZ(180deg) translateY(-65px) doesn’t equal to
transform: translateY(-65px) rotateZ(180deg).

Sass styles for the common hair:

/*** all hairs ***/
[class*="hair"]{
  display: block;
  position: absolute;
  left: 50%;
  top: 50%; 
  margin-left: -4px;
&::before{
    content: "";
    display: block;
    width: 16px;
    margin-left: -8px;
    height: 5px;
    border-radius: 50%;
    background-color: #000;
  }
&::after{
      content: "";
      display: block;
      position: absolute;
      left:50%; 
      transform: translateX(-50%);
      width: 4px; 
      margin-left: -4px; 
      height: 20px; 
      background-color: #000;
    }
}

hairs locations styles:

/*hairs location*/
.hair1 {transform: rotateZ(30deg) translateY(-65px);}
.hair2 {transform: rotateZ(60deg) translateY(-65px);}
.hair3 {transform: rotateZ(90deg) translateY(-65px);}
.hair4 {transform: rotateZ(120deg) translateY(-65px);}
.hair5 {transform: rotateZ(150deg) translateY(-65px);}
.hair6 {transform: rotateZ(180deg) translateY(-65px);}
.hair7 {transform: rotateZ(210deg) translateY(-65px);}
.hair8 {transform: rotateZ(240deg) translateY(-65px);}
.hair9 {transform: rotateZ(270deg) translateY(-65px);}
.hair10{transform: rotateZ(300deg) translateY(-65px);}
.hair11{transform: rotateZ(330deg) translateY(-65px);}
.hair12{transform: rotateZ(360deg) translateY(-65px);}

Because of the repetitions in the code of the hair, I thought it would be an excellent idea to use the “for” loop of Sass. For the developer who isn’t familiar with “for” loop of sass, it may seem uncomfortable at first, but in cases like this, it is worth it.

/* hair location */
$start-position: 0deg;
@for $i from 1 through 12{
   .hair#{$i}{
$start-position:  $start-position + 30deg;
     transform: rotateZ( #{$start-position} ) translateY(-65px); 
   }
 }

Current result:

Animating the Corona Virus

To give the virus a spirit of life, I added some animations. I created for every hair a separate animation. Besides this, every hair got a different negative animation-delay . This way, every hair will move at a different time.

CSS Animations Negative delay tell the browser to start the animation as if it already begun according to the time length of the negative delay value.

Again, I used here the same “for” loop of the hair, and added animations to it:

/* hair location */
$start-position: 0deg;
@for $i from 1 through 12{
  /* position hair */
  .hair#{$i}{
$start-position:  $start-position + 30deg;
    transform: rotateZ(#{$start-position}) translateY(-65px);
/* animate hair */
    animation: hairMove#{$i} 1s linear $i * -60ms infinite alternate; 
  }
/* different key-frames animation for every hair */
@keyframes hairMove#{$i} {
    from {transform:rotateZ(#{$start-position}) translateY(-68px);}
    to {transform:rotateZ(#{$start-position}) translateY(-61px);}
  }  
}

Current result:

Animating the Eyes

In the end, I added some more cute animations for the inner of the eyes, for the virus to have a silly look.

.eye1{
  &::before{
    left:10%;
    animation: eyeMove 1s linear 0s infinite alternate;
  }
}
.eye2{
  &::before{
    left:10%;
    animation: eyeMove 1s linear -0.5s infinite alternate;
  }
}
@keyframes eyeMove{
    0%  {transform: translateX(76%) translateY(10%);}
    20% {transform: translateX(50%) translateY(0%);}
    50% {transform: translateX(56%) translateY(30%);}
    70% {transform: translateX(50%) translateY(0%);}
}

Current result:

To create an even more realistic look, I added a closing eye animation that appears every 5 seconds. I did it with adding the second pseudo-element, ::after, of the eye. I created it as a black rectangle with height of 0px and only at the end of the animation it gets to full hight. In this way, I created the effect of a blinking eye.

/*** eyes ***/
[class*="eye"]{

  &::after{
    content: ""; 
    display: block; 
    height: 0px;
    background-color: #000; 
    animation: closeEye 5s linear 2s infinite alternate;
  }
}
@keyFrames closeEye{
  0%   { height:0%; }
  90%  { height:0%; }
  100% { height:100%; }
}

Current result:

Now the Coronavirus is like a living creature 🙂.

To the full CodePen of Creating Coronavirus Example:

To Summarize

In this article, my primary purpose was to show you how we can build CSS creatures.

Besides, it was my real first full experience of creating a CSS creature. Regularly, in my actual day job, I create CSS/HTML architectures, as I demonstrate in my previous article “Reverse Engineering WhatsApp Web’s CSS”.

Final Words

I hope I inspired you and showed you some new possibilities.
If you like this post, I would appreciate applause and sharing 🙂.

I create lots of content on CSS. Be sure to follow me via Twitter, Linkedin, and Medium.

Also, you can see all of my content on my website: eladsc.com.

Who Am I?
I am Elad Shechter, a Web Developer specializing in CSS & HTML design and architecture.

(Me talking at ConFrontJS 2019, Warsaw, Poland)

My Full CodePen Example — Coronavirus Invaders — CSS Pure Game:

Coronavirus Invaders — Pure CSS Game

Get More Content Like This

I’m starting a new community at CssClass.com.

Signup if you find it interesting 🤓
Articles, open-source projects, and deep-dive into CSS topics.

More content is coming soon at CssClass.com!