Creating a simple Christmas Tree with pure CSS

Alexandra Radevich
7 min readDec 4, 2020
The tree we’ll be making 🎄

Recently, I’ve gotten into making CSS art, or using CSS to create drawings and images — you can check out more of my stuff here. It’s fun, creative, and offers valuable practice for CSS positioning. Given this strange, never-ending year, I thought it’d be fun to create something festive and celebratory. Today, I’ll be walking you through how to create a Christmas Tree with CSS — feel free to tweak it and make it your own!

Above is the completed drawing and code — in case you just want to take a look at the code yourself.

HTML Structure

Before we can jump into styling, we first need to write our HTML. CSS art is all about breaking down an image into its most basic shapes, so that’s how we’ll organize our markdown.

First, we’ll have a wrapping container, which we’ll give a class of .container. This will house our tree, and in the case of our specific image, it’ll also have some styling applied to it, like the blue background.

Inside our container, we’ll have our tree, which will also get its own div.

Here’s what we have so far:

<div class="container">
<div class="tree"></div>
</div>

When we look at our tree in the final image, we can see that it’s really just made up of three triangles. So we can add three divs representing those triangles inside our tree.

Next, we can add a div for the trunk. And a div for the star at the top of the tree.

Our basic HTML is complete (we’ll add ornaments and some more details later).

<div class="container">
<div class="tree">
<div class="star"></div>
<div class="tree-triangle1"></div>
<div class="tree-triangle2"></div>
<div class="tree-triangle3"></div>
<div class="trunk"></div>
</div>
</div>

Styling our tree

Our container:

.container {
position: relative;
width: 380px;
height: 380px;

margin: auto;
margin-top: 20vh;
background: #0b1a5e;
border-radius: 120px;
z-index: -2;
}

You can leave most values for container until the end to play around with, but I highly suggest making sure you have the bolded ones in your code before moving forward. This is because we’ll be using absolute positioning and percentage based values on all of our tree elements — meaning that changing the width/height of our container later can skew our tree. I like to start with a square container, so that it’s easier to change the size without impacting the aspect ratio.

Here’s our container all styled — very impressive…

Next is the tree:

Now we’ll be turning our 3 triangle divs into actual triangles. There’s two ways to do this:

I’ll be using clip-path and this generator for my triangles. Here’s the code:

.tree-triangle3 {
position: absolute;
width: 66%;
height: 36%;
bottom: 20%;
left: 3.5%;
background: #034f33;
clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
}
.tree-triangle2 {
position: absolute;
width: 53%;
height: 33%;
bottom: 35%;
left: 10%;
clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
background: #046944;
z-index: 2;
}
.tree-triangle1 {
position: absolute;
width: 42%;
height: 25%;
bottom: 50%;
left: 15.5%;
background: #038052;
clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
z-index: 3;
}

Each triangle is positioned absolutely, so we can use top/bottom/right/left values to move them around. They also have a height and width, so that each triangle gets smaller as we move from the bottom triangle to the top. You’ll also notice the z-index value differs among the triangles, that’s because we want the top triangle to overlap the triangle underneath it.

The trunk:

Our trunk is just a rectangle that’s centered on the tree:

.trunk {
position: absolute;
width: 10%;
height: 16%;
background: #66503e;
z-index: -1;
bottom: 5%;
left: 32%;
}

I have a confession to make about centering — I just eyeball it! But if that bothers you or if you can’t shake the feeling that your art is off by a few pixels, there is a formula to centering:

left = (100 - width) / 2
top = (100 - height) / 2

You can read more about absolute centering and pure CSS images in this wonderful blog post.

The star:

I’m using clip-path and our handy generator again to get the shape right.

.star {
position: absolute;
width: 20%;
height: 20%;
background: #ffe380;
clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);
left: 26.5%;
top: 11%;
z-index: 4;
}

If you’re confused about the z-index here, it shouldn’t make a difference now. I’ll be adding a glow behind our star, which is why I want our star to be all the way on top of everything else. Right now though, it doesn’t matter.

Right now we should have this:

Now we just need to…

(Somewhere else being the center)

Centering our tree:

I haven’t forgotten about our .tree class div. It wraps around and is the parent of all the tree elements we just styled. So now, if we want to move the entire tree, we can manipulate the .tree div, instead of moving each single child element to where we want it.

.tree {
position: absolute;
width: 100%;
height: 100%;
left: 13%;
top: 5%;
}

Decorations

Now we get to decorate our beautiful CSS tree!

This will involve us adding some ornament divs inside our .tree div. I’m also adding a div inside each ornament with the class .shine, to give that 3D effect to the ornaments. This is totally optional.

Our HTML now:

<div class="container">
<div class="tree">
<div class="star"></div>
<div class="tree-triangle1"></div>
<div class="tree-triangle2"></div>
<div class="tree-triangle3"></div>
<div class="trunk"></div>
<div class="ornament or1">
<div class="shine"></div>
</div>
<div class="ornament or2">
<div class="shine"></div>
</div>
<div class="ornament or3">
<div class="shine"></div>
</div>
<div class="ornament or4">
<div class="shine"></div>
</div>
<div class="ornament or5">
<div class="shine"></div>
</div>
<div class="ornament or6">
<div class="shine"></div>
</div>
</div>
</div>

Each ornament will have a class of .ornament as well as an individual class (.or1, .or2 etc.). The individual class is for positioning the ornaments on the tree, and adding color. If you wanted all the ornaments to be the same color you could just add that to the .ornament class, but you’d still need the individualized classes for positioning.

Ornaments:

.ornament {
position: absolute;
width: 10%;
height: 10%;
border-radius: 50%;
box-shadow: 0 0 3px #033b26;
z-index: 4;
}
/* OPTIONAL */
.shine {
position: absolute;
width: 55%;
height: 55%;
top: 10%;
right: 11%;
border-radius: 50%;
background: white;
filter: opacity(60%)
}

We won’t see much from this code alone, besides a green circle in the upper left-hand corner of our container (with a white circle inside it if you chose to add shine). That’s because we haven’t established a background-color or position yet, let’s do that for our first ornament:

.or1 {
left: 28%;
top: 34%;
background: #0742d9;
}

Now we should have this:

Let’s add the rest of our ornaments:

.or2 {
left: 40%;
top: 45%;
background: #c91212;
}
.or3 {
left: 20%;
top: 49%;
background: #dbb700;
}
.or4 {
left: 34%;
top: 62%;
background: #0742d9;
}
.or5 {
left: 50%;
top: 69%;
background: #dbb700;
}
.or6 {
left: 15%;
top: 68%;
background: #c91212;
}

We’re almost there:

Styling and animating our star

We’ll need to add two more divs to our HTML, inside .tree (they can be right underneath our .star div).

<div class="star"></div>
<div class="star-highlight"></div>
<div class="star-light"></div>

.star-highlight is that slightly lighter half-star that takes up the right half of our star and adds some dimension.

.star-light is the circle of sheer glow around our star that we will be animating.

To get the half star we’ll be using clip-path and halving the appropriate values. Otherwise the code is very similar to .star.

.star-highlight {
position: absolute;
width: 20%;
height: 20%;
background: #fff1bf;
clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 50% 70%, 50% 60%, 50% 46%, 50% 36%);
left: 26.5%;
top: 11%;
z-index: 4;
}

Now for the glow, or .star-light:

.star-light {
position: absolute;
width: 20%;
height: 20%;
background: #fff1bf;
filter: opacity(.7);
border-radius: 50%;
left: 26.5%;
top: 11%;
z-index: 3;
animation: star 3s ease-in-out infinite;
}

We should now see a transparent yellow circle around our star. A few things to note:

  • We’re using filter to bring the opacity down and make the glow see-through.
  • Our z-index of 3 puts .star-light in-front of the tree but behind our star.
  • Our animation doesn’t work yet because we haven’t created it.

Animating the glow

We can see that .star-light uses an animation called star, we’ll use @keyframes to create it:

@keyframes star {
100% {
transform: scale(.5);
}
50% {
transform: scale(1.1);
}
0% {
transform: scale(.5);
}
}

This animation is simple, it uses the scale transform to manipulate the size of .star-light and make our star look like it’s glowing.

And that’s it! Our Christmas Tree is complete!

If you for some reason can’t get enough of CSS Christmas Trees (I’m not judging), check out some others that I’ve made below:

A pink version of our tree:

A tree that’s just one triangle:

Happy Holidays!

--

--