CSS Animated snake 🐍

— 12 minute read

Sometimes I want to experiment and feel how powerful CSS these days is.

So let's create something reasonably straightforward, but cool! A animated moving snake in CSS only.

Setting up the HTML permalink

To create our snake we are going to create one main snake div and add some dots in this, each dot will have it's own id so we can animate it better.

<div class="container">
<div class="snake">
<div class="dot dot-1"></div>
<div class="dot dot-2"></div>
<div class="dot dot-3"></div>
<div class="dot dot-4"></div>
<div class="dot dot-5"></div>
<div class="dot dot-6"></div>
<div class="dot dot-7"></div>
<div class="dot dot-8"></div>
<div class="dot dot-9"></div>
<div class="dot dot-10"></div>
<div class="dot dot-11"></div>
<div class="dot dot-12"></div>
<div class="dot dot-13"></div>
<div class="dot dot-14"></div>
<div class="dot dot-15"></div>
<div class="dot dot-16"></div>
<div class="dot dot-17"></div>
<div class="dot dot-18"></div>
<div class="dot dot-19"></div>
<div class="dot dot-20"></div>
</div>
</div>

CSS for a animated snake permalink

$numberOfDots: 20;
*
{
margin: 0;
padding: 0;
}
.container {
display: flex;
justify-content: center;
align-items: center;
width: 100vw;
height: 100vh;
background: #55d6be;
}
.snake {
.dot {
width: 12px;
height: 12px;
background: #fc6471;
border-radius: 50%;
margin: 5px 0;
&:nth-child(1)
{
width: 10px;
height: 10px;
background: #fff !important;
}
&:nth-child(odd) {
background: #090909;
}
}
}
@for $i from 1 through $numberOfDots {
$delay: 0.1 * $i;
.dot-#
{$i} {
animation: dot 1.5s infinite;
animation-delay: $delay + s;
}
}
@keyframes dot {
0%,
100%
{
transform: translateX(0);
}
50% {
transform: translateX(-15px);
}
}

This code is build in scss, we can compile this to plain css, but it will become very long, so for the sake of explaining what this does we will keep the scss stylesheet and explain what happens.

$numberOfDots: 20;

We define the number of dots (body parts) of our snake 🐍we can use this variable later on to loop each div, a handy feature of scss.

* {
margin: 0;
padding: 0;
}

The * selector is a global selector, it will select every element and in this case remove margin and padding from it.

.container {
display: flex;
justify-content: center;
align-items: center;
width: 100vw;
height: 100vh;
background: #55d6be;
}

As seen in many of my example we want to center our snake and I choose to center is with flexbox and use the 100vw and 100vh attributes.

.snake {
.dot {
width: 12px;
height: 12px;
background: #fc6471;
border-radius: 50%;
margin: 5px 0;
&:nth-child(1)
{
width: 10px;
height: 10px;
background: #fff !important;
}
&:nth-child(odd) {
background: #090909;
}
}
}

Our snake self has no styling, but each dot (body part) inside it consist of a basic width and height. We give it a pink color, and a border-radius: 50% which will make the div round! Then we add some margin so it's not stacked.

&:nth-child(1) { This is a psuedo-selector in this case we want the first child and make it slightly stronger and white, this will be the snakes head.

&:nth-child(odd) { again a psuedo-selector but this time we get every odd dot element and make it black, so 1,3,5... will be be black and 2,4,6... will be pink (the default).

@for $i from 1 through $numberOfDots {
$delay: 0.1 * $i;
.dot-#
{$i} {
animation: dot 1.5s infinite;
animation-delay: $delay + s;
}
}

So as mentioned we are using the variable here, we are going to loop through 1 to 20 and calculate a custom delay for each dot.

Then we say each dot should have the dot animation which will play for 1.5seconds infinite (never stops)

Uncompiled it will look like this:

.dot-1 {
animation: dot 1.5s infinite;
animation-delay: 0.1s;
}
.dot-2 {
animation: dot 1.5s infinite;
animation-delay: 0.2s;
}
.dot-3 {
animation: dot 1.5s infinite;
animation-delay: 0.3s;
}
...

And then we add a unique animation-delay to each dot this will increase for each dot.

@keyframes dot {
0%,
100%
{
transform: translateX(0);
}
50% {
transform: translateX(-15px);
}
}

This is the part that makes the snake move.

We make our own @keyframe animation called dot and say at position 0 and 100% it should do transform: translateX(0); on position 50% it should transform: translateX(-15px);. The translateX will move the dot -15px to the left at 50% and fill the gaps in between 0-50 and 50-100% so it will look smooth.

See a working example in this Codepen:

See the Pen CSS Animated snake 🐍 by Chris Bongers (@rebelchris) on CodePen.

Thank you for reading, and let's connect! permalink

Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on Facebook or Twitter