How to create an animated moon with CSS and JavaScript (Step by Step)

- Andrés Cruz

ES En español

How to create an animated moon with CSS and JavaScript (Step by Step)
In this tutorial, you will learn how to create an animated Moon using only CSS for the design and animations, and a touch of JavaScript to generate a dynamic starry background. We will explore the use of box-shadow (both outer and inner) to achieve relief and depth effects in a simple yet effective way.

Modern web design is not just about static structures; small animations and visual details, like this experiment of a moon with craters and phases, add a layer of interaction that improves the user experience. Below, we will see how to achieve this effect step by step.

Building our Moon in three steps

1. The base structure and the lunar halo

It all starts with a simple circular div. To give it that "glowing" look, we will use the box-shadow property. Instead of a solid color, we will apply a pulsing animation that emulates the natural glow of the moon on a clear night.

I have modernized the positioning using left: 50% and transform to ensure the moon is always centered regardless of the container size:

#moon {
    position: absolute;
    top: 15%;
    left: 50%;
    transform: translateX(-50%);
    width: 200px;
    height: 200px;
    border-radius: 50%;
    background: #CCC;
    box-shadow: 0 0 100px #FFFF8C;
    z-index: 5;
    animation: moonPulse 3s infinite ease-in-out;
}
@keyframes moonPulse {
    0%, 100% { box-shadow: 0 0 80px #FFF; }
    50% { box-shadow: 0 0 120px #FFF; }
}
 

2. Craters and depth with Box-Shadow Inset

For the craters, the secret lies in the box-shadow: inset property. This creates an internal shadow that gives the sensation of a hollow without the need for complex images or SVGs. Additionally, we add a top layer to simulate lunar phases using shadows.

#moonFase {
    position: absolute;
    top: 15%;
    left: 50%;
    transform: translateX(-50%);
    width: 200px;
    height: 200px;
    border-radius: 50%;
    background: rgba(153, 153, 153, 0);
    /* Internal shadow for phase effect */
    box-shadow: inset -25px 0px 0 0px #999;
    z-index: 6;
    animation: moonFaseAnimation 600s infinite linear;
}
.crater {
    position: absolute;
    background: #555;
    box-shadow: inset 3px -2px 0 0px #414043;
    z-index: 7;
    border-radius: 50%;
}

SEO and Performance Tip: By using pure CSS instead of heavy images, we reduce page load time, a key factor for Google ranking.

3. Dynamic starry background with Modern JavaScript

Positioning 250 stars manually would be inefficient. Therefore, we use a small script that generates stars in random positions. I have updated the original code to ES6 using const and DocumentFragment to minimize browser "reflows," improving performance.

const generateStars = () => {
    const w = window.innerWidth;
    const h = window.innerHeight;
    const fragment = document.createDocumentFragment();
    for (let i = 0; i < 250; i++) {
        const star = document.createElement("div");
        star.className = "star";
        
        // Random positioning
        const x = Math.floor(Math.random() * w);
        const y = Math.floor(Math.random() * h);
        
        star.style.bottom = `${y}px`;
        star.style.right = `${x}px`;
        
        fragment.appendChild(star);
    }
    document.body.appendChild(fragment);
};
generateStars();

The style of the stars remains minimalist, but with a slight glow so they appear to twinkle:

.star {
    width: 2px;
    height: 2px;
    border-radius: 50%;
    background: #FFF;
    box-shadow: 0 0 2px 1px rgba(255, 255, 255, 0.8);
    position: absolute;
}

Taking it further: Customization

This experiment is the perfect foundation for practice. You can try changing the moon's color to a reddish tone for a "lunar eclipse," or modify the speed of the phase animation. If you want to dive deeper into the world of animations, I recommend reading my article on how to take your first steps with CSS animations.

Did you like this tutorial? Don't forget to also check out how to highlight content in an animated way with CSS to keep improving your web design skills.

In this entry we will see how to create a Moon which will be composed of its halo, craters, phases and a starry sky.

I agree to receive announcements of interest about this Blog.

Andrés Cruz

ES En español