In this article, we will see how to make a responsive cartoon of Santa Claus using HTML and CSS. Like this one:
We will do it step by step, explaining each shape and each decision (or almost of all of them). Because, after all, the image is just a combination of elements with different shapes.
Let's start by...
Setting the canvas
By canvas, I don't mean a <canvas>
element, but a canvas in which to do our painting. This will be helpful because we can use it as a reference for our elements once it is set.
If we use relative units for canvas and content, we will be actually creating a responsive image with CSS. That's the reason why most of the units used in this drawing are going to be %
or vmin
.
As a drawing helper, we can add a repeating-linear-gradient
to create a background grid which will be useful for positioning elements:
Note: The canvas must have a relative or absolute position to place the different elements where we want.
For the colors, we are going to use CSS variables. They will allow us to have consistent colors and will facilitate changes.
Drawing the head
The head will be multiple circles and ellipses: a big circle for the face, smaller circles for the eyes, and ellipses for the cheeks.
To round objects and make them circular or elliptical, we use border-radius
with a value of 50% or higher.
We could have the eyes and cheeks inside the face, and then their size would be relative to the parent instead of the canvas, but we will keep everything at the canvas level for now.
We create a circle for the face, another for one eye, and an ellipse for one of the cheeks. Then we use box-shadow
to duplicate the second eye and cheek:
The beard and mustache
In this section, we will use two basic CSS shapes that are really useful for drawing: the oval and eye shapes for the beard and mustaches, respectively.
The beard will go behind the head. To achieve the oval shape, we take advantage of border-radius
taking two values separated by /
: one for the horizontal axis and another for the vertical.
Note: when we say that the box-shadow takes two values, each value can have 1-4 sub-values... which may make it look like there are 8 values. By two values, we mean two sets of up to 4.
The mustaches will go on top of the head. There will be two elements with basically the same styles (just different rotation) next to each other. The adjacent sibling combinator (+
) will go perfect for this.
Our Santa Claus starts looking like Santa already.
Drawing the hat
The hat is going to be a single element, but it will include two pseudo-elements: ::before
and ::after
.
This is convenient because their size and position will be relative to the hat, and changing a single component will update all three of them at once. We could have 3 elements (hat, base, and pompom), but this way, we practice pseudo-elements.
Important:
::before
and::after
must have acontent
property or they won't be displayed. It's ok if the value is empty, but it needs to be there.
The hat is a basic square in which one corner (top left) has a border-radius of 100%, creating a nice curvature. The pompom is just a circle. So the trickiest part is the bottom of the hat.
For the bottom, we are going to use a shape I call a pipe. We draw it by having a square and adding two values for the border-radius: 100% / 50%
. This way, the square's top and bottom will be curved while the sides will be flat.
Once we have that shape, we add an inset box-shadow from the top. Then we'll have that curved bottom. We may need to rotate it a little to adjust it to the head:
We added a blue-ish background so we can see the bottom of the hat and the pompom.
The body
The body shape is like a bell, which is basically an oval with small bottom corner radii in CSS.
But that's not the interesting part about the body. We are going to draw the belt and the buttons section using CSS gradients: radial-gradient()
and linear-gradient()
respectively.
The buttons section is a simple left-to-right linear gradient using three colors: transparent, then white, and then transparent again. Leaving a small % between the colors to add some "blurry" effect.
The belt is a bit trickier: it is a circular (radial) gradient, and we'll have to play with the values to position it exactly where we want. It follows a similar transparent-color-transparent pattern as the buttons section:
With that, we have the body. But it looks a bit boring. It's time to improve it by...
Adding details to the body
The first detail is going to be the buttons. It is going to be a single rounded element with different shadows. We used a similar technique for the eyes, but instead of horizontally, the shadows will go vertically.
The belt buckle is just a rectangle! We add golden borders, a little bit of border-radius (we don't want an ellipse). The background will also be gold, but with an inset box-shadow
, we highlight the prong.
Checking some Santa drawings, many have the bottom of Santa's jacket as white. So we expand the radial-gradient
from the body, so it ends in white instead of transparent:
As a final step, we added a clip-path
to snip the bottom of the buttons section, so it looks like the jacket overlaps.
Arms and hands
The arms will be a single element with the same shape as the body: a bell. But this bell is going to be shorter and wider. That way, when we place it behind the body, it will "overflow" on the sides.
Adding a small vertical gradient from transparent to semi-transparent black, the arms get some color distance from the body. The gradients make it look like a shadow and emphasizes the backward position.
The hands are a simple circle again. Same routine as the eyes or the buttons. I could have gone for something slightly more complicated (or even an ellipse), but I have to confess I'm terrible at drawing hands... so the circle will do:
Now the top part of our Santa is complete. This would even make a cute element for a website (e.g., animating it up from the bottom of the page.)
Drawing the legs
The legs will have two parts: the leg in itself and the boot tip (only the tip, because the boot will be drawn with a linear gradient on the leg itself).
We draw rectangles for the legs, distance them a little (using the adjacent sibling combinator that we used before for the mustaches), add a red-black gradient to separate pants and boots... and slightly tilt them with skew()
, so they don't look too symmetrical.
Finally, for the boot tip, we use the ::after
pseudo-element, rounding the top corners:
With this, our Santa is complete... but it looks a bit sad just by itself floating in that gray void. Let's add some scenery.
Adding the ground and some snow
Let's start with the ground because it is easier. We don't even need a new element! We can use the ::before
pseudo-element of the canvas.
We will make it really big. So big that it will overflow the viewport, and we will need to add overflow: hidden
to the document's <body>
to avoid annoying scrollbars.
Then we will place it at the bottom of the canvas and add a tiny curvature to it (by making it an inverted bell!) And just like that, we have our Santa standing on a hill.
The snow is also a fairly simple step. We will create it by adding a bunch of radial gradients to the <body>
, each of them a background image with different sizes (so they seem more irregular).
Note:
background-image
allows for more than one value as long as they are separated by commas. Same principle applies tobackground-position
,background-repeat
,background-size
...
The result looks like this:
And with that, our drawing is complete. We need to clean up a little, removing the grid that served as guidelines.
Animating the scene
We have complete a static drawing... but we can add some animations to make it pop up:
- Santa could blink as a normal person does
- Moving the mustaches now and then shaking that cold
- It would be a lot cooler if the snow actually fell
Blinking is a simple animation, making the eye's height from whatever it is to zero and then back. We may need to add a vertical translation for a better experience.
Moving the mustaches is also a simple animation, but it starts getting "messy" because we need to synchronize both mustaches (remember it is a two-part thing!) Playing with the times and the angles will yield great results.
As for the snow, we can animate the background-position
to make it look like it's falling. Doing it vertically is easy, but it doesn't look too realistic. Snow zigzags when falling, so we will add that zigzagging to our animation.
Note: the real challenge with animation is timing. If all the animated parts have the same timing functions and last for the same amount of time, the animation looks fake. Mixing things make it look more natural and nicer... Unfortunately, I'm not that great at it. For reference, you can check the work on Adam Kuhn, Sarah Drasner, or Jhey Tompkins. They are really amazing.
With all the animations listed above, our animated cartoon looks nicer:
It is important to consider the will of the user and disable the animations if they chose so (especially taking into account accessibility). We can do that with the prefers-reduced-motion
media feature.
And that's it! We have created an animated scene with Santa Claus and, during this process, we have practiced a lot of CSS:
- Animations
- Backgrounds
- Border-radius
- Box-shadow
- Combinators
- Gradients
- Overflow
- Positioning
- Pseudo-elements
- Transforms
- Units & colors
- Variables
You can see the code of the final demo on this JSFiddle.
Top comments (5)
Amazing work, More power to you for this hard-work and I really like the idea of js-fiddles
Thanks!
Perfect, keep it up
Please, make it a web component.
I'd need to look into this. Sounds like a nice learning challenge. Thanks for the suggestion.