A Beginner’s Guide to Pure CSS Images

Michael Mangialardi
Coding Artist
Published in
18 min readJan 7, 2017

--

What you’re getting into: 17 min read. A detailed explanation of how to creating pure CSS images. We will start with an overview and work our way to create a Koala in pure CSS.

What I assume you know: My teaching method is to not assume you know basic principles. Unless you are a complete novice with HTML and CSS, I don’t make any assumptions.

If you’re not a beginner: I will be repeating basic principles often. Just skim past the parts that are easy for you and keep in mind this is meant to help people of all skill ranges.

Video Course

Pure CSS Images Video Course: In this video course, I go over everything you need to know about pure CSS images.

Introduction

There often seems to be a line drawn between a vector artist and a front-end developer. The reason being that many jobs have enough hands, and work, on deck to make such a separation for the sake of productivity. Another main factor being that some people want to really focus on front-end development and others want to be really specific to illustration. Even in both areas, there are specific niches one can focus on to develop a really good and valuable skill-set.

There is definitely much prudence to this, however, I think that a front-end developer would benefit greatly from working on illustration even if not their main focus.

I think this is the case because both skills are essentially putting together different components to create a final product. Vector illustrators put together various shapes, and manipulations on shapes, to create a final illustration. Front-end developers put together coded components to form a web page.

Learning to make vector graphics teaches you about layouts, color palettes, manipulations of shapes, and overall creativity which does have a carry over to front-end development.

While I should probably carry this discussion of benefits of vector illustration for front-end developers, I bring it up since pure CSS images are an example where the intersection between vector illustrators and front-end developers is really close.

Creating a pure CSS image is essentially designing a vector graphic but instead of using vector illustration software (i.e Illustrator, Affinity Designer, Sketch) you are using CSS code in place of your toolbar.

Despite the close intersection, I think that a vector illustrator can see a ton of CSS code to create an image as daunting and a front-end developer can see creating graphics with code as daunting as well.

For this reason, I will give a tutorial on designing your first pure CSS image, which I hope accomplishes any of the following:

  1. Boost confidence for creating pure CSS images
  2. Provide a better understanding of how pure CSS images work
  3. Increase curiosity for vector illustration as a front-end developer
  4. Increase curiosity for front-end development as a vector illustrator
  5. Provide a basic template to create more pure CSS images

The Components of a Pure CSS Image

First off let’s explain what exactly does “pure CSS” mean?

The “pure CSS” refers to creating an image simply by adding style via CSS to several divs in your HTML.

For example, we can create a square with just one HTML div and styling applied to the div with a CSS class:

With pure CSS images, we will be creating shapes by styling HTML divs with purely CSS in order to form a final image.

Each pure CSS project will consist of the following components:

  1. A HTML div for each shape
  2. A specific CSS class assigned to each HTML div
  3. CSS classes containing styling for according HTML div
  4. An invisible box that will serve as the canvas (will make more sense later…I promise)

Here is the final pure CSS image we will be creating that contains only the components listed above:

But before we start coding, let’s break down the specific shapes that make up this Koala image.

Note: If you prefer video, you can access this as a video tutorial on our free pure CSS images video course.

Shape Composition

First, the entire image of the Koala will be built on top of an invisible square canvas (not official terminology). This invisible box will be centered on the body of the HTML and the head will be centered on the box. I personally find this to be good practice as it simplifies responsive design, which I will describe at the end of this post.

For now just keep in mind that there will be an invisible rectangle box which I have outlined below:

Second, we have a circle in the center of the webpage that will create the head.

Next, there will be ears on each side of the head. Each ear is composed of two different colored circles on top of each other, with one circle slightly smaller than other. We will distinguish between an ear div and inner ear div.

Additionally, we will have two eyes that are also two circles on top of each other. We will distinguish between eye, the larger white circle, and pupil, the smaller black circle.

Next, we will create the nose which will be a brown rounded rectangle just under the eyes.

Lastly, we will have two pieces of gray hair which will be two differently located triangles on the top of the head.

Another important thing to mention is that there are different layers to this image as well. The ears will be behind the head, the nose will be in front of the eyes, etc. This will be explained as we do the CSS styling.

The HTML

Note: To add the hair to our koala image, we are going to use a clip-path method. This method is supported by Chrome, Safari, and Opera. If you are using Firefox, switch over to one of the supported browsers, preferably Chrome, to code along this guide.

Typically, I work by inserting a single div that will serve as a shape, then I will style that shape in the CSS, and then proceed to inserting the next div.

However for the sake of instruction, let’s take a look at the HTML at once and break it down.

<body>
<!-- Begin Image -->
<!-- Invisible Box-->
<div class="box">

<!-- Circular Head-->
<div class="head">

<!-- Circular Head Copy -->
<div class="head-copy"></div>

<!-- Left Ear ~ Light Gray-->
<div class="ear-left">

<!-- Inner ear ~ Dark Gray -->
<div class="inner-ear"></div>
</div>

<!-- Right Ear ~ Light Gray-->
<div class="ear-right">
<!-- Inner Ear ~ Dark Gray-->
<div class="inner-ear"></div>
</div>

<!-- Left Outer Eye ~ White -->
<div class="eye-left">
<!-- Pupil ~ Black -->
<div class="pupil">
</div>
</div>

<!-- Right Outer Eye ~ White -->
<div class="eye-right">
<!-- Pupil ~ Black -->
<div class="pupil">
</div>
</div>

<!-- Nose ~ Brown -->
<div class="nose">
</div>

<!-- Hair ~ Light Gray -->
<div class="hair-left"></div>
<div class="hair-right"></div>

<!-- End Head -->
</div>
<!-- End Invisible Box -->
</div>
</body>

It is crucial to notice that some divs are nested in between other divs. For instance, let’s look at our right ear div:

<!-- Right Ear ~ Light Gray-->
<div class="ear-right">
<!-- Inner Ear ~ Dark Gray-->
<div class="inner-ear"></div>
</div>

There is the beginning tag of <div class=”ear-right”> that contains <div class=”inner-ear></div> before the closing tag. Ear-right is the parent div and inner-ear is a child div.

The reason this is important is because shapes will be given fixed locations, widths, and heights that are percentage based. The percentage applies to the parent div.

For example, let’s say we have a div that is nested in between the body and the body is set to 100% height and 100% width:

The some-div class assigns a fixed position that is 10% from the top. Since the some-div is nested between the body that is 100% height and 100% width, the div will be 10% below from the top of the screen.

Now let’s nest another div in between some-div and then assign it an absolute position of 10% from the top.

We will get an entirely different location as you can see:

In this example, another-div (blue square) is 10% below the some-div (red square).

Now let’s remove another-div from being nested under some-div, nest it under the body, and change the top percentage to 30%.

Another-div (blue square) is now 30% from the top of the screen and not 30% under some-div (red square).

With this in mind, let’s get to the CSS styling.

CSS Styling

Body
To start off our styling, let’s give our body a background color of Twitter-ish blue.

body{
background: #25A9FC;
}

Box
Next, we will style the invisible box. The invisible box will be centered horizontally due to the following code is what allows it to be horizontally centered (note: if you are following along to visually see how the position of the box changes, you can either set a background color for the box or add a solid border):

.box{
position: relative;
margin: auto;
display: block;
//optional background or borderbackground: white;
border: solid 4px red;
//add more code here}

Position relative means the element is positioned relative to its normal position, which would be the very top left corner as it is the first div in the body.

When the position is set to relative, using display: block; and margin:auto; will automatically center the box horizontally.

We can then add the following to make the box be 8% lower as well as set the height and width with the dimensions shown in the image above, and lastly assigning a background of.

.box{
position: relative;
margin: auto;
display: block;
margin-top: 8%;
width: 600px;
height: 420px;
background: none;
}

One thing to note is that we used margin-top: 8% to lower the box by 8%. Since we are specifically adjusting the top margin, it will not effect our previous margin:auto which was used to center the box. If we did margin: 8% then the margin:auto would be overwritten.

Now that our box is set, all of our other divs will be nested within the box. Again this is important as we will assign an absolute positions (top, right, left, or bottom) by percentage that will position a div that percentage from the box and not the body. The same concept will also apply with our height and width percentages.

Recommendation
If you have the luxury, I highly recommend placing a live image on an external monitor. This can be done if you host locally or if you have a pro account on Codepen, you can change view to “Live View” to see your pen in full width and with instant updates. If not, you will have to make do.

Head
Let’s look at the code for the head div and then break it down piece by piece.

.head{
position: absolute;
top: 16.5%;
left: 25%;
width: 50%;
height: 67%;
background: #A6BECF;
border-radius: 50%;
}

The percentages for top and left mean that the div will be 15% from the top of the box and 25% from the left of the box.

The width of the div is 50% and the height 67%. Again, this means that the width is 50% of the box and the height 67% of the box.

After that we set the background to a light gray color.

Then, we use border-radius: 50%. If you left border-radius out, the div would always be the shape of a rectangle (or square). The border-radius is what curves the shape. If you are familiar with Illustrator, adding a border-radius is like pulling the corner of a square to round it. To round it down to a circle, we always use a percentage of 50%.

Border-radius can be used not only to make circles, but to round any shape, like the rounded-rectangle we will get to when we style our nose div.

Now before we go any further, you might be wondering where in the world I got these percentages for top, left, width, and height. Let’s think about it.

We gave the box a width of 600px, so a width of 50% gives it a width of 300px. Given that the box was only 400px in height, the height percentage for the head will have to be higher.

Now is the part where you may be expecting me to give you a very precise formula for determining how I got the height, but to be honest, I usually just guess with good old trial and error.

The more you make pure CSS images, the better estimations you can do. But all you really need to think through is knowing the height and width of the parent div and what size the current child div needs to be in relation to the parent div.

Now with position percentages when you want to absolutely center, it’s a bit easier to calculate. Here is the formula:

left = (100 - width) / 2
top = (100 - height) / 2
//in our case
(100 - 67)/2 = top: 16.5%;
(100-50)/2 = left: 25%;

Now this works for our head div because we want it dead center. However, we aren’t going to want to dead center our ears, for example. We will get to this shortly which will also explain when to use bottom and right instead of top and left.

The last thing to mention in this section is that every div that follows will be nested under this head div since each shape that will be added will be on top of the head.

Here is what we should have at this point:

Learning Timeout
I know this a lot at once, but let’s continue to chug away and see how everything comes together. If you need to take a break, feel free to bookmark this blog post or use Pocket to save for later.

Head Copy

.head-copy{
width: 100%;
height: 100%;
position: absolute;
background: #A6BECF;
border-radius: 50%;
z-index: 2;
}

The head copy is div is solely for the purpose of allowing the ears to appear behind the head. This is controlled by z-index.

The last line of our style was the following:

z-index: 2;

Z-index is used to indicate the depth of the div. If you are an illustrator this will make a lot of sense if you think about how layers work.

Our final image will have eyes in front of the head, nose in front of the eyes, etc. This will be controlled by z-index. The higher the z-index value, the closer that div is to the top.

So if you had 2 divs, z-index: 1 would be like your bottom layer and z-index: 2 would be your top layer.

Since our bottom layer will be the ears, we will be giving it z-index: 1. If we omitted the head-copy div, add gave the head div a value of z-index 2, the ears won’t be behind the head. However when we add head-copy and give that the value of z-index: 2, our ears will be behind the head.

I wouldn’t get too worked up if this is confusing, if you’d like you can take out head-copy when we add the ears to see for yourself.

We shouldn’t see any changes and still have the following image:

Ears
As discussed in the beginning when we broke down our shapes, one ear for each side that will consist of top circles. Two bigger, light gray circles (ear-left and ear-right) and two smaller, dark gray circles on top of each ear respectively (inner-ear).

.ear-left{
position: absolute;
width: 60%;
height: 65%;
left: -20%;
top: 5%;
background: #A6BECF;
border-radius: 50%;
z-index: 1;
}
.ear-right{
position: absolute;
width: 60%;
height: 65%;
right: -20%;
top: 5%;
background: #A6BECF;
border-radius: 50%;
z-index: 1;
}.inner-ear{
position: absolute;
border-radius: 50%;
width: 80%;
height: 80%;
top: 10%;
left: 10%;
background: #819CAF;
}

For each CSS class, we use border-radius: 50% since they are all circles and then we add a color using background.

As you can see, there is styling for two separate ears but only one for the inner ear. This will make sense as we break down positioning.

Ear-left and ear-right’s parent div is head. Therefore, it will be positioned by percentages relative to the head, as well as a height and width relative to the head.

The height and width can be estimated since we want big ears, but still smaller than our head. This gives us width: 60%; and height: 65%;

The inner ear is nested under ear-left and ear-right. We know we want it to be slightly smaller so we give it a height and width of 80%. We also know we want the inner ear dead centered relative to the ears so we can use the formula again.

left = (100 - width) / 2
top = (100 - height) / 2
//in our case
(100 - 80)/2 = top: 10%;
(100-80)/2 = left: 10%;

Because our top and left are relative to the ears, we can use the same style under both ear-left and ear-right, which is why there is only one inner-ear div. We have to use two separate ear divs because they will have different left and right position values since they are positioned relative to the head.

We want both ears to be sticking out to the left and right of the head accordingly. Therefore, we use negative percentages, left: -20% and right: -20%. Meaning, each ear will shift 20% of the width of the head in the specified direction.

This is probably obvious, but I never like to assume. Whenever you have left and right divs like this you can position one side, like left: -20%, and then copy and paste the style for that div, rename the class for the other side, and then just change the left to right or vice versa.

Here are the positions and sizes for the ears once all is said and done:

//left ear
width: 60%;
height: 65%;
left: -20%;
top: 5%;
//right ear
width: 60%;
height: 65%;
right: -20%;
top: 5%;

Lastly we added z-index: 1; so that our ears will go behind the head. We should now have:

Eyes

.eye-left{
position: absolute;
background: white;
width: 30%;
height: 33%;
top: 25%;
left: 21%;
border-radius: 50%;
z-index: 3;
}
.eye-right{
position: absolute;
background: white;
width: 30%;
height: 33%;
top: 25%;
right: 21%;
border-radius: 50%;
z-index: 2;
}
.pupil{
position: absolute;
width: 28%;
height: 30%;
top: 35%;
left: 36%;
border-radius: 50%;
background: #27354A;
}

You can see that our eyes are similar to our ears. We have two big, white circles (eye-left and eye-right) and one pupil.

For all of them, we use border-radius: 50%; since they are circles and we use background to give the appropriate colors.

We have one pupil since it is nested under each eye. We guesstimate the height and width of the pupil and then dead center it which gives us:

width: 28%;
height: 30%;
top: 35%;
left: 36%;

For eye-left you can either use trial and error for the top and left positioning. Or you could use the dead center formula and adjust the values depending on the distances from the center. Meanwhile, the width and height were just estimated till it was just right.

//left eye  
width: 30%;
height: 33%;
top: 25%;
left: 21%;

//right eyes
width: 30%;
height: 33%;
top: 25%;
right: 21%;

As for the z-index, the following values will allow for the nose to be on top on the eyes:

//left eye 
z-index: 3;
//right-eye
z-index: 2;

We should now have the following image:

Nose

.nose{
position: absolute;
background: #BE845F;
width: 25%;
height: 42.5%;
left: 37%;
top: 45%;
border-radius: 50px;
z-index: 4;
}

Now for the nose, we guesstimate the height and width relative to the head. Once this is known, you can either guess or dead center and adjust accordingly. The following values give us a good size and location:

width: 25%;
height: 42.5%;
left: 37%;
top: 45%;

Again we style the brown color using background and specify the depth with z-index: 4; so that the nose is on top of the eyes.

We also used border-radius: 50px; which will round the corners of the rectangle as needed. When only rounding slightly, it is much easier to use round by px instead of a percentage.

By now we should see the following image:

Hair
Almost done! The last step is to add style our two pieces of hair, hair-left and hair-right, which will give us a completed Koala image.

.hair-left{
position: absolute;
top: -8%;
left: 30%;
width: 20%;
height: 20%;
background: #A6BECF;
-webkit-clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
}
.hair-right{
position: absolute;
top: -4%;
left: 48%;
width: 20%;
height: 20%;
background: #A6BECF;
-webkit-clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
}

As you can see, there is no border-radius, but we do have this clip-path line:

-webkit-clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
clip-path: polygon(50% 0%, 0% 100%, 100% 100%);

For any shape outside of a square, rectangle, and circle, it is easiest to use clip-path.

Note: This method supported by Safari, Chrome, and Opera but not Firefox. While this may be a bummer, this is going to be the easiest method to learn how to make shapes with purely CSS.

Now, this may look confusing, but fortunately, there is a great tool that will automatically give us the clip-path for different shapes.

Open this tool called Clippy in a new tab.

You will see on the right-hand side that you can select from a whole host of shapes:

In the image above, the triangle shape is selected and you can copy and paste the clip-path on the bottom and paste into the hair CSS classes.

Once again, we do the color with background and estimate the height and width of 20% for both. We give the hair-left a left value of 30% and the hair-right a left of 48%. This brings up a good example to discuss whether we use left or right. Let’s say we want the hair-right further to the right by 5%, we could add 5% to 48% to get left: 53%. However as a good rule of thumb, whenever you get past 50% switch to right. So left: 53% would be equivalent to right: 48%. For this example, let’s keep it at left: 48% and carry on.

The top positions are going to be negative since we want both pieces of hair sticking out above the head. Hair-left will be sticking out a bit more so we give it top: -8%; and hair-right will be a bit lower with top:4%;

Our Koala image is now complete.

Final CSS:

body{
background: #25A9FC;
}
.box{
position: relative;
margin: auto;
display: block;
margin-top: 8%;
width: 600px;
height: 420px;
background: none;
}.head{
position: absolute;
top:16.5%;
left: 25%;
width: 50%;
height: 67%;
background: #A6BECF;
border-radius: 50%;
}
.head-copy{
width: 100%;
height: 100%;
position: absolute;
background: #A6BECF;
border-radius: 50%;
z-index: 2;
}
.ear-left{
position: absolute;
width: 60%;
height: 65%;
left: -20%;
top: 5%;
background: #A6BECF;
border-radius: 50%;
z-index: 1;
}
.ear-right{
position: absolute;
width: 60%;
height: 65%;
right: -20%;
top: 5%;
background: #A6BECF;
border-radius: 50%;
z-index: 1;
}.inner-ear{
position: absolute;
border-radius: 50%;
width: 80%;
height: 80%;
top: 10%;
left: 10%;
background: #819CAF;
}
.eye-left{
position: absolute;
background: white;
width: 30%;
height: 33%;
top: 25%;
left: 21%;
border-radius: 50%;
z-index: 3;
}
.eye-right{
position: absolute;
background: white;
width: 30%;
height: 33%;
top: 25%;
right: 21%;
border-radius: 50%;
z-index: 3;
}
.pupil{
position: absolute;
width: 28%;
height: 30%;
top: 35%;
left: 36%;
border-radius: 50%;
background: #27354A;
}.nose{
position: absolute;
background: #BE845F;
width: 25%;
height: 42.5%;
left: 37%;
top: 45%;
border-radius: 50px;
z-index: 4;
}
.hair-left{
position: absolute;
top: -8%;
left: 30%;
width: 20%;
height: 20%;
background: #A6BECF;
-webkit-clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
}
.hair-right{
position: absolute;
top: -4%;
left: 48%;
width: 20%;
height: 20%;
background: #A6BECF;
-webkit-clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
}

Further Practice

Hopefully, this gives you a good concept of how pure CSS images work and inspires you to learn more. Additionally, you should now have a nice template that you can tweak to get more practice.

Here are some resources I have created for some structured practice:

  1. Pure CSS Images Video Course: In this video course, I go over everything you need to know about pure CSS images.

--

--