I recently hit the halfway point in my 100 days of CSS art journey - I've learned a lot since I started - you can read about it in my last post:
5 lessons from 50 days of CSS art
Suzanne Aitchison ・ Jul 4 '20 ・ 4 min read
I know first-hand it can be intimidating getting started with CSS art, and hopefully in this post I'll show you it's totally achievable, as we make this cute wee sheep, step by step.
What you'll learn by making this sheep
- Some key positioning techniques
- Making use of
::before
and::after
pseudo elements - Utilising CSS custom properties (variables)
- One way clip-path can help you create shapes
Checkpoints after each step
At the end of each of the 5 steps there is a CodePen showing you both the code and result of what we've covered up til the end of that step, so you won't get left behind!
If there is anything unclear in the instructions, do skip to that CodePen and take a closer look; hopefully all will become clear.
Step 1: Set up your canvas
Start a new pen in CodePen (or wherever you like to create your code!). The first step is to get ready with your "canvas" - i.e. the area of the page you will create your image inside.
Choose a background color
First we'll set the body
element's background color - I chose a nice grass green, but feel free to use whatever funky color you like!
body {
background: #54a865;
}
Create a box and position center
I've created a div
with the classname "sheep" to act as our canvas. Width and height has been set to 180px, and we'll give it some margin too so it looks nice on the page.
<body>
<div class="sheep"></div>
</body>
.sheep {
position: relative;
margin: auto;
display: block;
margin-top: 8%;
margin-bottom: 8%;
width: 180px;
height: 180px;
}
Note the property position: relative
. This is important, as inside the canvas we will be using absolute positioning. By setting the position to 'relative' here, the content of our canvas will be positioned relative to this canvas.
Give yourself a guide by adding a temporary canvas background
I've set the background of the 'sheep' to pink
for now, purely so I can see exactly where the canvas is, and check it's positioned correctly. Choose whatever color stands out to you!
Work in progress - end of step 1:
Check what you should have so far:
Step 2 - Make some fluff
The most important part of a sheep? The fluff!
The fluff on this sheep is going to be made in two halves - left side and right side. On each side we will have three overlapping circles, like so:
Add a CSS variable for the fluff size
As we can see above, we'll have six total fluff pieces, all of which will be the same size. When you have a property that is going to be shared across multiple CSS selectors, it's a good idea to create a CSS property/variable for them.
This allows you to easily access and change the property in one place, without having to go through multiple places in your code.
We can create this fluff size variable at the root of the document like so:
:root {
--fluff-size: 70px;
}
Now whenever we want to access the fluff size (e.g. for the width and height of all the fluff pieces) we can use var(--fluff-size)
to get it!
Create the middle fluff pieces
The middle fluff pieces will be created with div elements:
<div class="fluff left"></div>
<div class="fluff right"></div>
The shared fluff
class will contain the majority of our styles:
.fluff {
position: absolute;
width: var(--fluff-size);
height: var(--fluff-size);
border-radius: 50%;
background: white;
top: 50px;
}
Then we can use the extra left
/right
class names to position each side correctly.
The left side is going to be positioned at left: 0
. Since this is the default for an absolute-positioned element, we don't need to add anything - yay!
The right side is going to be positioned at the right, which we can do as so:
.fluff.right {
right: 0;
}
Create the upper fluff sections
To do this, we're going to use the ::before
pseudo element. I'm using this purely to cut down on the amount of HTML code. Using .fluff::before
will place an element as the first child of any element with the .fluff
class - e.g.
<div class="fluff left">
<!-- ::before fluff appears as if entered here -->
</div>
We want to position the upper fluff elements slightly higher than the parent .fluff
divs, and also more towards the center.
We can use the shared fluff
class to do most of the work:
.fluff::before {
content: "";
position: absolute;
width: var(--fluff-size);
height: var(--fluff-size);
border-radius: 50%;
background: white;
top: -35px;
}
And then once again we can make use of the left
/right
classes to move each side closer to the center, as so:
.fluff.left::before {
left: 35px;
}
.fluff.right::before {
left: -35px;
}
Create the lower fluff sections
This is very similar to the previous step. This time we'll use the ::after
pseudo element. Using .fluff::after
will place an element as the last child of any element with the .fluff
class - e.g.
<div class="fluff left">
<!-- ::before fluff appears as if entered here -->
<!-- ::after fluff appears as if entered here -->
</div>
Similar to the above step, we'll use main fluff
class to specify the majority of styles, and the left/right classes to push each lower fluff piece into the center.
Work in progress - end of step 2:
With that - our fluff is created - see what we have so far:
Step 3 - Add a head with ears
Now we have some fluff, but we need a head! We'll use a div with class name head
to create this, and style it as round and black.
.head {
position: absolute;
width: 70px;
height: 70px;
background: black;
border-radius: 50%;
}
We'll also once again use ::before
and ::after
pseudo elements - this time to make the ears.
The ears are ovals with a black background color. To make sure we keep the width and height the exact same on both, let's make some more variables for them:
:root {
--fluff-size: 70px;
--ear-width: 15px;
--ear-height: 20px;
}
Position the head
We want to make sure that the head is positioned in the center of the body. One way do that would be to crunch some numbers and work out exactly how many pixels to the left we want to place it.
An easier way (in my opinion) would be to use the following:
left: 50%;
transform: translateX(-50%);
What this does is:
- Use the
left
property to set the start position of the head to 50% of the parent div (i.e. the canvas we created in step 1). Our canvas is 180px wide, so this would be the same asleft: 90px
- Use the
translateX
transform to move the head to the left. The amount it moves to the left is 50% of the head's width. Our head is 70px wide, so this is the same astranslateX(-35px)
- The combination of the two places the center of the head (i.e. 35px) in the center of the parent
Work in progress - end of step 3:
You can check the ear positioning and sizes in the CodePen below, or try choosing your own first! After this step you should have something like:
Step 4: Add some face features!
We want a happy smiley sheep, so lets add some eyes first. We'll use very similar style as before, creating two HTML elements inside the head:
<div class="head">
<div class="eye left"></div>
<div class="eye right"></div>
</div>
We'll use a border to help it look like a dark pupil inside of a white eye:
.eye {
position: absolute;
background: black;
border: 5px solid white;
height: 10px;
width: 10px;
border-radius: 50%;
top: 15px;
}
You can then use the left
and right
classes to position each eye how you like (check the work in progress CodePen below if you're not sure though!)
Use clip-path to create the mouth
clip-path
can be a very useful CSS property. It effectively creates a mask for your HTML element, allowing only a portion of it to be shown.
In this case, we're going to use it to turn a block into a semi-circle.
Let's start with an HTML element <div class="mouth"></div>
inside the head. We'll style it as a white block, and position in the center of the head just like we did with the in Step 3.
.mouth {
position: absolute;
left: 50%;
transform: translateX(-50%);
background: white;
width: 30px;
height: 30px;
}
Use Clippy to create your mouth shape
Clippy is an awesome tool for creating clip-path code easily. Visit the site, select the circle option from the right, and drag the element around to create the semi circle shape you want.
The code it generates should look a bit like:
clip-path: circle(50% at 50% 0);
Feel free to choose another shape for the mouth and play around with Clippy to your heart's content!
Once you're ready, add the clip-path
property to the CSS for .mouth
, and adjust the vertical positioning to suit. Here's what I have now:
.mouth {
position: absolute;
bottom: -10px;
left: 50%;
transform: translateX(-50%);
background: white;
width: 30px;
height: 30px;
clip-path: circle(50% at 50% 0);
}
Work in progress - end of step 4
You're nearly at the finish line! So far, you should have something like this:
Step 5: Add the legs and finish up!
There's no new techniques here, and the code for the legs should look fairly familiar by now. You'll need to create two new HTML elements:
<div class="leg left"></div>
<div class="leg right"></div>
Make sure you place these before the fluff elements and the rest of the code you created. This makes sure they sit behind everything else.
Each leg is a black rectangle, with a slight border radius to remove any sharp corners:
.leg {
position: absolute;
top: 120px;
height: 50px;
width: 15px;
background: black;
border-radius: 30%;
}
We can then use the left
/right
classes to position each leg. I've used the same positioning trick we looked at in step 3 to make the legs sit at 30% in from each side, i.e.
.leg.left {
left: 30%;
transform: translateX(-30%);
}
.leg.right {
right: 30%;
transform: translateX(30%);
}
Tidy up
Now you have all your elements in place, it's time to clean up by removing that pink background we added to the canvas in step 1, and deleting any extra code comments you don't want any more!
Ta da!
You should now have a finished sheep, a little bit like this:
Congratulations! If this is your first piece of CSS art, seriously - WELL DONE!
Round up
Let's take a look at what techniques you can now re-use in your CSS art to come:
- Positioning items vertically and horizontally, including with % values
- Using clip-path to make shapes
- Using
::before
and::after
to save lots of extra HTML elements - Using CSS variables
Awesome!
Thanks for following along to the end - if you do create a wee sheep through this tutorial I would absolutely love to see it! Drop your codepen link in the comments so we can all revel in its glory 😃🐑