Loading Spinner using Emojis – Tutorial

Loader Emojis

Creating a fun and visually appealing loading spinner using emojis can add a unique touch to your website, application, or digital project. In this tutorial, we will use clock face emojis to simulate a loading spinner. This method is both simple and highly customizable, allowing you to adjust the speed, size, and emojis used. Let's dive in!

Step 1: Choose Your Emojis

For our spinner, we'll use the clock face emojis to represent different times of the day, creating the illusion of a spinning clock. The emojis we'll use are:

  • 🕛 Noon
  • 🕐 1:00
  • 🕑 2:00
  • 🕒 3:00
  • 🕓 4:00
  • 🕔 5:00
  • 🕕 6:00
  • 🕖 7:00
  • 🕗 8:00
  • 🕘 9:00
  • 🕙 10:00
  • 🕚 11:00

You can find a complete list of emojis over at CharacterCodes.net.

Step 2: Create the HTML Structure

Create a simple HTML structure where your loading spinner will be displayed. Inside a container div, we will dynamically insert our emojis using CSS code (explained further below).

<div class="loader">
  • The HTML code defines a div element with a class of loader. This is the container for our emoji loader.

Step 3: Add CSS for Animation

Next we need to add some CSS to animate our emojis. We'll break this code into two sections, the first section will be the code for the loader div container and secondly we will explain the keyframe animation that changes the content property to cycle through the emojis.

.loader::before {
  position: absolute;
  width: 1em;
  height: 1em;
  left: 50%;
  top: 50%;
  font-size: 4rem;
  transform: translate(-50%, -50%);
  content: "";
  animation: spinEmoji 1.5s steps(12, end) infinite forwards 0s;
  • position: absolute; positions the ::before pseudo-element absolutely relative to its nearest positioned ancestor (in this case, the .loader div if it has a position other than static). This allows for precise positioning of the element.
  • width: 1em; height: 1em; sets the width and height of the pseudo-element to 1em, which means it will be square with its size relative to the font size of the element.
  • left: 50%; top: 50%; positions the center of the pseudo-element in the center of the .loader div.
  • font-size: 4rem; sets the font size of the content within the pseudo-element to 4rem, making it relatively large based on the root element's font size.
  • transform: translate(-50%, -50%); moves the pseudo-element up and to the left by half its own width and height, effectively centering it perfectly within the .loader div.
  • content: ""; is necessary for the ::before pseudo-element to be generated. Initially, it doesn't contain any text content.
  • animation: spinEmoji 1.5s steps(12, end) infinite forwards 0s; applies an animation called spinEmoji to the pseudo-element. This animation lasts 1.5 seconds for each cycle, uses a stepping function with 12 steps that happen at the end of each interval, repeats an infinite number of times, moves in a forwards direction at the end of each iteration (meaning it retains the styles set by the final keyframe), and starts immediately (0s delay).
@keyframes spinEmoji {
  0% { content: '🕛'; }
  8.333% { content: '🕐'; }
  16.666% { content: '🕑'; }
  25% { content: '🕒'; }
  33.333% { content: '🕓'; }
  41.666% { content: '🕔'; }
  50% { content: '🕕'; }
  58.333% { content: '🕖'; }
  66.666% { content: '🕗'; }
  75% { content: '🕘'; }
  83.333% { content: '🕙'; }
  91.666% { content: '🕚'; }
  100% { content: '🕛'; }
  • 0% and 100%: At the start (0%) and end (100%) of the animation, the content is set to '🕛', representing 12 o'clock. Having the same emoji at 0% and 100% ensures a smooth, continuous loop.

  • 8.333% to 91.666%: Between these percentages, the content property changes through a sequence of clock face emojis from '🕐' (1 o'clock) to '🕚' (11 o'clock). Each step represents an equal fraction of the animation's total duration (1.5s), with the emojis changing at intervals of 8.333%, which divides the animation into 12 equal parts for the 12 hours.

The effect of this animation is a "spinning" clock face, with the emoji changing to the next hour at each step, giving the impression of time passing. The steps(12, end) timing function specified in the animation property of .loader::before ensures that the animation jumps directly from one emoji to the next without any interpolation in between, making each emoji appear for an equal portion of the animation cycle before switching to the next.

So now that we have seen the code necessary to create our loader, just click on the button below to visually see it in action.

Demo of Loader

Step 4: Customize Your Spinner

You can customize your spinner by adjusting the animation duration in the animation property. A shorter duration will make the spinner rotate faster, while a longer duration will slow it down. You can also adjust the font size to make the spinner larger or smaller.


By utilizing CSS animations, you've created a smooth and visually appealing loading spinner using emojis, with reduced reliance on JavaScript. This method is excellent for simple animations and can be easily adapted or extended with more complex CSS or combined with JavaScript for enhanced interactivity.