DEV Community

loading...
Cover image for Making a popsicle with CSS only!

Making a popsicle with CSS only!

Eva Thora Karlsdottir
🇮🇸 Icelandic full-stack developer based in Belgium 🇧🇪
・5 min read

Getting creative with CSS illustrations

Even though CSS illustrations might not be ideal for production (let's face it, a simple SVG is a lot less painful), they are a great way to improve your CSS skills and let your creative spirit fly!

The project

In this project we'll make a refreshing popsicle with a small animation on hover.

Setting up the HTML

We start with setting up the HTML. In this case, the structure is simple:

<div class="container">
  <div class="popsicle-container">
    <div class="popsicle-top"></div>
    <div class="popsicle-base"></div>
    <div class="stick"></div>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

We have one general container which we'll use to center the popsicle. The popsicle itself is composed of the .popsicle-container which contains three div elements:

  1. .popsicle-top
  2. .popsicle-base
  3. .stick

These are the only HTML elements we'll need for this project.

Moving on to the CSS

The container is a flex box which takes the whole width of the viewport and both centers and aligns our popsicle in the middle of the screen:

.container {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
}
Enter fullscreen mode Exit fullscreen mode

The .popsicle-container is very similar, except there we'll set the flex-direction to column so our elements will stack below one another. We'll also set the height and width of the popsicle.

.popsicle-container {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  height: 30rem;
  width: 12rem;
}
Enter fullscreen mode Exit fullscreen mode

Now our wrappers are ready and we can move on to the fun stuff!

How do we capture the depth?

We want our popsicle to have proper dimensions. In order to achieve this, we'll be using two pseudo-elements: ::before and ::after.

What are pseudo-elements?
Pseudo-elements are hidden elements (think of them like ghosts that hang around your element). Like the names suggest, ::before appears before the element and ::after goes after it. Pseudo-elements are very useful for decorative purposes (like in our popsicle). However they are not always picked up by screenreaders so avoid putting any crucial information in them.

Let's start with the .popsicle-base.

We will put most of the properties in the ::before and ::after elements so the .popsicle-base itself will contain the width and the height. We will also need to be able to link the position of the ::before and ::after elements to the .popsicle-base, so we'll give it a position: relative;.

.popsicle-base {
  position: relative;
  height: 20%;
  width: 100%;
}
Enter fullscreen mode Exit fullscreen mode

The .popsicle-base::before element will be the shaded part of the popsicle.

.popsicle-base::before {
  content: '';
  position: absolute;
  width: 100%;
  height: 100%;
  background-color: #ffbdce;
  border-bottom-right-radius: 10%;
  border-bottom-left-radius: 10%;
  transform: skewY(-5deg);
}
Enter fullscreen mode Exit fullscreen mode

All before and after elements need the content property. Without it they won't be displayed. So, all we need to do is to set it to an empty string. We'll set the radius on the bottom borders to make it a bit rounded and add a nice pink background colour. We set postion: absolute; so it'll be relative to the .popsicle-base (we will fix the exact positioning once we have the after element). We'll also slightly skew the Y axis to create the angle needed on the shadow.

This is what we have so far:
slightly skewed pink rectangle

Now for the .popsicle-base::after

We'll give it a bit of depth by putting an ellipse shaped gradient at the top of the element. Besides the background colour and the gradient, the ::after element has all the same properties as the ::before. So we can simplify the code above to this:

.popsicle-base::before, .popsicle-base::after {
  content: '';
  position: absolute;
  width: 100%;
  height: 100%;
  border-bottom-right-radius: 10%;
  border-bottom-left-radius: 10%;
  transform: skewY(-5deg);
}

.popsicle-base::before {
  background-color: #ffbdce;
}

.popsicle::after {
  background: radial-gradient(ellipse at top, rgba(241, 240, 
  240, 0.74), #ffcbd8 60%);
  background-color: #f3f3f3;
}
Enter fullscreen mode Exit fullscreen mode

And here's what we have now.
A skewed pink rectangle with white radial shading at the top
You might think, wait, where's the first rectangle?

It's there! It's just hidden behind the ::after element. In order to make it visible we'll need to shift the ::before element a bit to the right. We'll also push it a tiny bit upwards.

.popsicle-base::before {
  background-color: #ffbdce;
  right: -1.5rem;
  top: -0.1rem;
}
Enter fullscreen mode Exit fullscreen mode

The result is a nicely shaded and slightly skewed rectangle:
A pink rectangle with slightly darker right side

Doing the same for the .popsicle-top and .stick

The .popsicle-top follows the same logic except we put the gradient at the bottom of the element so that it blends with the other gradient:

.popsicle-top {
  position: relative;
  height: 60%;
  width: 100%;
  border-top-left-radius: 35%;
  border-top-right-radius: 35%;
}

.popsicle-top::before, .popsicle-top::after {
  content: '';
  position: absolute;
  width: 100%;
  height: 100%;
  border-top-left-radius: 35%;
  border-top-right-radius: 35%;
  transform: skewY(-5deg)
}

.popsicle-top::before {
  right: -1.5rem;
  background: #86c8e4;
}

.popsicle-top::after {
  background: radial-gradient(ellipse at bottom,  rgba(241, 
  240, 240, 0.74), rgba(152, 208, 241, 0.877) 80%);
  background-color: #97DFFC;
}
Enter fullscreen mode Exit fullscreen mode

What we have so far:
A blue and pink popsicle which is missing the stick

The stick is also the same but there we also add a bit of shading on the top of the stick to make it's placement with the popsicle more realistic:

stick::before, .stick::after {
  content: '';
  position: absolute;
  width: 100%;
  height: 100%;
  border-bottom-left-radius: 10%;
  border-bottom-right-radius: 10%;
  box-shadow:
  inset 0 0 1rem rgb(236, 187, 113),
  inset 0 0.5rem 0.7rem -0.3rem rgba(0,0,0,0.4);
  transform: skewY(-5deg)
}

.stick::after {
  background-color: #F3D4A5;
}

.stick::before {
  right: -0.5rem;
  background-color: rgb(219, 183, 128);
}
Enter fullscreen mode Exit fullscreen mode

With that we have our lovely popsicle:
A blue and pink popsicle

Adding animation

We'll add a small pulsating animation where we slightly decrease the size and then increase it again.

@keyframes pulse {
  0% {
    transform: scale(1);
  }
  60% {
    transform: scale(0.95);
  }
  100% {
    transform: scale(1);
  }
}
Enter fullscreen mode Exit fullscreen mode

We'll then apply it on the .popsicle-container on hover with a 2 second duration and on an infinite loop (as long as the element is in the hover state):

.popsicle-container:hover {
  animation: pulse 2s ease-in infinite;
}
Enter fullscreen mode Exit fullscreen mode

That's it!

I hope you've enjoyed making this colourful popsicle :)

Discussion (0)