• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar
  • Skip to footer

The Coding Couple

Pair programming is a lifetime commitment.

  • Home
  • Categories
    • Arduino
    • JavaScript
    • Python
    • Raspberry Pi
  • About Us
    • Privacy Policy
  • Contact

Snow Globe Single DIV CSS Drawing with Animating Snowflakes | Tutorial

December 16, 2021 by Ashley

Learn how to draw a snow globe with a single div and CSS.

Snow globe single div drawing

In this blog post I will walk you through how I created a snow globe with animating snowflakes using one div and a bunch of CSS.

With the holidays right around the corner, I wanted to create something festive. I went back and forth between a Christmas tree or a snow globe and settled on a snow globe.

For this tutorial, I will be picking up right where I left off from my previous blog post: CSS Magic with a Single DIV. In that tutorial, I covered the basic building blocks of single div drawing:

  • pseudo-elements
  • box-shadows
  • background and gradients
  • …and more.

Now, let’s get started!

Drawing a Snow Globe with CSS

It’s helpful to break down the object you intend to draw into basic shapes. In the case of the snow globe, there are two main shapes:

  • a circle for the globe
  • a quadrilateral for the base

Step 1: Create the basic shapes of the snow globe

With our basic shapes in mind, it’s time to draw them. First add a div for the drawing on the page.

<div></div>

At its core, single div drawing is just drawing in layers. The globe portion of our snow globe is overlapped by our base. I’ll style the div for the globe and use a pseudoelement for the base.

body {
    height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background: dodgerblue;
}

/* snow globe */
div {
    height: 50vh;
    width: 50vh;
    border-radius: 50%;
    background: white;
}

/* snow globe base */
div::before {
    content: '';
    position: absolute;
    top: 65%;
    left: 25%;
    width: 50%;
    height: 25%;
    background: burlywood;
}

(There’s a small quirk to using the psuedoelements. The content property is required or else there is nothing to draw. Assigning it an empty string will suffice.)

Our globe looks really basic. Let’s refine it with gradients. We’ll start with the base and move up to the globe.

Basic shapes of the snow globe

Step 2: Transform the base into a trapezoid

The look I am going for the base is the shape you get if you sliced off a portion of a cone from the base up. If you were to look at that shape from dead on, it would like a trapezoid.

One way we can turn our rectangle into a trapezoid is using the transform property. Here’s an article that can explain this technique better than I. I will use the perspective and rotateX functions to create a shape that looks like a trapezoid, but it’s really just a rectangle with a different viewing angle.

transform: perspective(75px) rotateX(10deg);
Transform the rectangle to look like a trapezoid for the base

The transformation altered the size of the base, so I made a few more tweaks to div::before pseduoelement to get the shape you see above.

div::before {
    content: '';
    position: absolute;
    top: 65%;
    width: 50vh;
    height: 15%;
    background: burlywood;
    transform: perspective(75px) rotateX(10deg);
}

Step 3: Add dimension to the base with gradients

The base to the snow globe is flat and boring. With linear gradients, we can add some fun dimensions to the base.

To make the base look more like a conical shape, we’ll apply a linear gradient that runs from the left to right of the shape.

background-image: 
    linear-gradient(90deg, saddlebrown, 
                           chocolate, 
                           transparent, 
                           chocolate, 
                           saddlebrown);
Linear gradient applied to the base of the snow globe

Now, that looks better. However, while it’s no longer flat in appearance, the base is still looks a little boring. A nice touch would be adding a small ridge to the top and bottom of the base. We can do this with the help of an another gradient. With the background-image (or background) property, we can apply multiple layers of a gradients. The first gradient in the background-image property is the topmost gradient.

We’ll need to make use of the background-position and background-size properties to properly arrange the new additions to the base.

background-image: 
    /* Top ridge */
    linear-gradient(saddlebrown, transparent, saddlebrown),
    /* Bottom ridge */
    linear-gradient(saddlebrown, transparent, saddlebrown),
    /* Main base */
    linear-gradient(90deg, saddlebrown, 
                           chocolate, 
                           transparent, 
                           chocolate, 
                           saddlebrown);
background-size: 
    /* Top ridge */
    100% 15%,
    /* Bottom ridge */
    100% 10%,
    /* Main base */
    100% 100%;
background-position:
    /* Top ridge */ 
    0 0,
    /* Bottom ridge */
    0 100%,
    /* Main base */
    0 0;
background-repeat: no-repeat;
Top and bottom ridges added to the base

We’re done with the base for now. Let’s revisit the globe.

Step 4: Add a radial gradient to the globe

For the globe, we’ll use a radial gradient. Replace the white background color with a radial-gradient.

background: radial-gradient(transparent 45%, white);

I used a stop of 45% over the default so only the edges of the circle will have a “frosted glass” look.

Radial gradient added to the snow globe

Step 5: Add a layer of snow to the base of the globe.

Next up, we need to add a layer of snow to the inside of the globe. For this we’ll use a linear-gradient. We can manipulate the gradient stops to only draw at the lower portion of our globe.

background: 
    radial-gradient(transparent 45%, white),
    linear-gradient(transparent 70%, white 71%);

If the gradient stop for the white color was set to 70%, there would be a harsh solid division between the transparent and white portions of the gradient. With 71%, it softens the transition ever so slightly such that it’s not too jarring or too fuzzy.

A layer of snow added to the snow globe

Step 6: Add snowflakes

My original thought for the snowflakes was to create squares and multiply them, but then I discovered there is a unicode character for a snowflake.

Three in fact:

  • U+2744 (snowflake)
  • U+2745 (tight trifoliate snowflake)
  • U+2746 (heavy chevron snowflake)

To make use of the unicode characters in the single div, we can use inline SVG.

(Is it cheating to use SVG in single div drawings?)

SVG has a text element and we can add multiple SVGs to our background property. There is one small caveat to using inline SVG: it must be URL encoded. Fortunately, I found a handy tool, from the github user yorkel, to take care of the all the tedious work.

SVG URL encoder tool

The SVG for drawing a snowflake is pretty simple. With the following SVG input:

<svg height='40' width='40'>
    <text x='0' y='15' fill='black'>&#x2744; 
    </text>
</svg>

The SVG URL encoder outputted:

background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='40' width='40'%3E%3Ctext x='0' y='15' fill='black'%3E&%23x2744; %3C/text%3E%3C/svg%3E");

Add the URL encoded SVG to the background image. I created an inline SVG for each snowflake variant.

background: 
    radial-gradient(transparent 45%, white),
    linear-gradient(transparent 70%, white 71%),
  /* Snowflake Style U+2744 */
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='50' width='50'%3E%3Ctext x='0' y='15' fill='lightcyan'%3E&%23x2744;%3C/text%3E%3C/svg%3E"),
    /* Snowflake Style U+2745 */
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='40' width='40'%3E%3Ctext x='0' y='15' fill='white'%3E&%23x2745;%3C/text%3E%3C/svg%3E"),
    /* Snowflake Style U+2746 */
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='60' width='60'%3E%3Ctext x='0' y='15' fill='linen'%3E&%23x2746;%3C/text%3E%3C/svg%3E");
Snow globe with stationary snowflakes

Step 7: Animate the snowflakes

Our drawing is really starting to come together. To bring it to life, let’s animate the snowflakes’ positions.

div {
    [ a bunch of other stuff... ]

    animation: animate-snowflakes 35s linear infinite alternate;
}

@keyframes animate-snowflakes {
    to {
      background-position:
        0 0,
        0 0,
        20% 50%,
        75% 50%,
        50% 100%;
    }
}
Snowflakes with linear animation

Step 8: Add the final touches

We still have a whole pseduoelement (div::after) we can leverage for drawing additional elements like a small plaque on the base, or an object inside of the snow globe.

div::after {
    position: absolute;
    content: 'Christmas 2021';
    font-family: 'Oleo Script Swash Caps', cursive;
    text-align: center;
    width: 10%;
    height: 1.5rem;
    left: 45%; 
    bottom: 22%; 
    color: #331F01;
    background: gold;
    background-image: 
      linear-gradient(90deg, goldenrod, transparent, goldenrod);
    border: 2px outset goldenrod;
    padding: 4px 0;
}
Plaque added to snow globe base

Also to add a little more depth to the snow globe, we can make use of the box-shadow property.

Add this box-shadow to both the div and div::before styles:

  box-shadow: 0 0 55px 10px dodgerblue;

And finally, update background for the body element to use a linear gradient too:

  background: linear-gradient(dodgerblue, midnightblue);
Snow globe single div drawing

Tinker with project over at codepen.io:

See the Pen Single DIV Snow Globe with animating Snowflakes by Ashley Grenon (@townsean) on CodePen.

Related Posts

  • Pokémon Color Picker | A web app built with HTML/CSS + JavaScriptPokémon Color Picker | A web app built with HTML/CSS + JavaScript
  • Trijam #261 Game Jam Diary: One Wrong MoveTrijam #261 Game Jam Diary: One Wrong Move
  • CSS Magic with a Single DivCSS Magic with a Single Div
  • Error: [🍍]: “getActivePinia()” was called but there was no active PiniaError: [🍍]: “getActivePinia()” was called but there was no active Pinia
  • Uncaught TypeError: util.inherits is not a functionUncaught TypeError: util.inherits is not a function
  • Southeastern Technical Conferences & Events (2016 Edition)Southeastern Technical Conferences & Events (2016 Edition)

Filed Under: HTML and CSS, Programming Languages Tagged With: animation, christmas, html, snow globe

Previous Post: « CSS Magic with a Single Div
Next Post: Uncaught TypeError: util.inherits is not a function »

Primary Sidebar

Social Media

  • GitHub
  • Instagram
  • Twitter
  • YouTube

Recent Posts

  • Pokémon Color Picker | A web app built with HTML/CSS + JavaScript
  • Pokéball Single DIV CSS Drawing | Tutorial
  • Error: [🍍]: “getActivePinia()” was called but there was no active Pinia
  • Trijam #261 Game Jam Diary: One Wrong Move
  • Using WSL on Corporate VPN

Recent Comments

  • Lizzy on Creation Crate Month 2: An Arduino Powered Memory Game
  • Ashley Grenon on Creation Crate Month 2: An Arduino Powered Memory Game
  • Lizzy on Creation Crate Month 2: An Arduino Powered Memory Game
  • kelly on Creation Crate Month 2: An Arduino Powered Memory Game
  • Ashley on Creation Crate Month 3: An Arduino Powered Distance Detector

Follow us on Instagram!

This error message is only visible to WordPress admins

Error: No feed found.

Please go to the Instagram Feed settings page to create a feed.

Categories

  • Arduino
  • Conferences
  • Debugging
  • Game Jams
  • HTML and CSS
  • JavaScript
  • Programming Languages
  • Python
  • Raspberry Pi
  • Today I Learned

Archives

  • May 2024
  • April 2024
  • March 2024
  • May 2022
  • December 2021
  • May 2021
  • March 2020
  • January 2020
  • December 2019
  • November 2019
  • October 2019
  • June 2019
  • April 2019
  • September 2017
  • April 2017
  • August 2016
  • July 2016
  • June 2016
  • May 2016
  • April 2016
  • March 2016
  • April 2015
  • January 2015

Tags

adafruit arduino brackets c# code smell codestock coding standards conventions creation crate debugging developer devspace electronics es6 es2015 game development game jam gotcha hackathon hoisting html html5 javascript led naming conventions nintendo phaser pluralsight pokemon programmer python raspberry pi retro retropie scope self improvement single div single div drawing subscription box TIL today I learned troubleshooting vue vuejs windbg

Footer

About Us

We are the Coding Couple.  Two people who met in college and decided they wanted to pair program for the rest of their ...

Read More »

Most Recent Posts

Pokémon Color Picker | A web app built with HTML/CSS + JavaScript

Pokéball Single DIV CSS Drawing | Tutorial

Error: [🍍]: “getActivePinia()” was called but there was no active Pinia

Trijam #261 Game Jam Diary: One Wrong Move

Social Media

  • GitHub
  • Instagram
  • Twitter
  • YouTube

Copyright Notice

© The Coding Couple, 2015 – 2023. Excerpts and links may be used, provided that full and clear credit is given to The Coding Couple with appropriate and specific direction to the original content.

Copyright © 2025 · Foodie Pro Theme by Shay Bocks · Built on the Genesis Framework · Powered by WordPress