Click here to Skip to main content
15,114,302 members
Articles / Web Development / CSS
Posted 2 Jan 2021

Tagged as


11 bookmarked

A pure CSS Solar System

Rate me:
Please Sign up or sign in to vote.
5.00/5 (16 votes)
2 Jan 2021CPOL6 min read
A webpage representing the Solar system made in pure CSS
This is a web model of solar system made entirely in CSS.


This project has no practical purpose, it's merely my attempt to play around with CSS, learning different CSS techniques. I am not a web designer and have only had a couple of takes on CSS – in other words, I am a complete newbie to CSS, so please bear this in mind.

That being said – this is exactly what it says in the title – a pure CSS model of Solar system, with the Sun, the planets, simulation of rotation, planet tilts, textures, etc. Probably it could have been done better, but as I said, I am a newbie, I think it's fair to say it's not a bad work.

The sizes, the distances and the tilts are an approximation and do not resemble the true appearance of the Solar system. I have tried to maintain the ratio between the distances, although to be able to make the page viewable, I used, to some extent, a sort of exponential scale. This goes for the size of the planets as well – except, of course, the Sun, which is much larger. I have taken over the info from Google and Wikipedia, but might be also that there are some mistakes in this data, so feel free to point them out. Also, I am open to any suggestions on how to improve this and maybe add some new features.

IMPORTANT NOTE: I am using textures and background images that were randomly found on the Internet, meaning that I don't have the ownership of these images nor have any influence on the URLs. In other words, the page might break eventually if the images disappear or the URLs become invalid, in that case they can easily be substituted in the code by other URLs.


I always admired those CSS artists that make magic using pure CSS and making it work despite its simplicity and many limitations, so I wanted to make an attempt at this myself. I wouldn't call this an artwork, but it is surely a nice introduction to the power of CSS.

Using the Code

The HTML Part

The HTML code is basically minimal, as the idea was to do most or all of the magic by using CSS.

Each of the planets (plus the Sun) are represented as span elements, with names as ids and class=“planet“. The textures are represented as inset div elements, class=“texture“. Next to each span there is also a div element of class=“text“, which contains some basic info about the planet; these text class elements also have the same ids as the span elements – they are referenced by using both id and class name.

Also, there is an additional div for Saturn, which is used to represent the Saturn's ring.

<span class="planet" id="sun"><div class="texture"></div></span><div class="text" id="sun">
Sun<br>Diameter: 1,392,700 km<br>Rotation cycle: 27 days</div>
<span class="planet" id="mercury"><div class="texture"></div></span>
<div class="text" id="mercury">Mercury<br>Diameter: 4,879 km<br>
Rotation cycle: 59 days<br>Distance from Sun: 67,062,000 km</div>
<span class="planet" id="venus"><div class="texture"></div></span>
<div class="text" id="venus">Venus<br>Diameter: 12,104 km<br>
Rotation cycle: 243 days<br>Distance from Sun: 108,000,000 km</div>
<span class="planet" id="earth"><div class="texture"></div></span>
<div class="text" id="earth">Earth<br>Diameter: 12,742 km<br>
Rotation cycle: 24 hours<br>Distance from Sun: 147,120,000 km</div>
<span class="planet" id="mars"><div class="texture"></div></span>
<div class="text" id="mars">Mars<br>Diameter: 6,779 km<br>
Rotation cycle: 25 hours<br>Distance from Sun: 226,028,000 km</div>
<span class="planet" id="jupiter"><div class="texture"></div></span>
<div class="text" id="jupiter">Jupiter<br>Diameter: 139,820 km<br>
Rotation cycle: 10 hours<br>Distance from Sun: 763,000,000 km</div>
<span class="planet" id="saturn"><div class="texture"></div></span>
<div class="ring" id="saturn"></div><div class="text" id="saturn">Saturn<br>
Diameter: 116,460 km<br>Rotation cycle: 11 hours<br>
Distance from Sun: 1,4914,000,000 km</div>
<span class="planet" id="uranus"><div class="texture"></div></span>
<div class="text" id="uranus">Uranus<br>Diameter: 50,724 km<br>
Rotation cycle: 17 hours<br>Distance from Sun: 2,957,700,000 km</div>
<span class="planet" id="neptune"><div class="texture"></div></span>
<div class="text" id="neptune">Neptune<br>Diameter: 49,244 km<br>
Rotation cycle: 16 hours<br>Distance from Sun: 4,476,000,000 km</div>

The CSS Part

Global Variables

All of the sizes, distances, rotation speeds and tilts of the planets (and Sun) are defined in the :root pseudo-class, which represents the HTML document and is primarily used for defining globally visible variables.

:root {
        --rotation-sun: 600s;
        --tilt-sun: -0.1265364;
        --tilt-earth: -0.40910518;
        --tilt-jupiter: -0.05462881;
        --tilt-neptune: -0.49427724;
        --tilt-mercury: -0.0005235988;
        --tilt-venus: -0.04607669;
        --tilt-mars: -0.43964844;
        --tilt-saturn: -0.46652651;
        --tilt-uranus: -1.4351842;

This is done so in order to be able to change it more easily, if necessary.

The data is taken from various sources on the Internet – the distances and sizes are a rough approximation based on an exponential scale; tilts are defined as radians.

Shape, Size and Position

All the elements' (classes') positions are defined as absolute, which means they are positioned relative to their nearest ancestor. They are positioned as 50% from the top, and translated 50% of their sizes upward, to make sure they are positioned vertically at the center. The border-radius is set as 50% to represent a circular shape. Overflow is hidden to make sure that the texture is only visible inside the circle (their span ancestors).

.planet {
    border-radius: 50%;

.planet, .text, .ring {
    position: absolute;
    top: 50%;
    margin: auto;
    overflow: hidden;
    transform: translateY(-50%);

Shadow Effect

Each planet has a shadow set at their side opposite from the Sun. To add the shadow, we are using the :after pseudo-element on each span.

The position is, again, absolute. We are using top/bottom/left/right distances as 0 to make sure that the shadow starts from the borders of the ancestor. The border-radius is again 50% to ensure the circular appearance.

The most important part here is the box-shadow property:

box-shadow: none|h-offset v-offset blur spread color |inset|initial|inherit;

h-offset is the horizontal offset of the shadow, we need it to be negative in our case to put the shadow inside. I am using for this purpose 20% of the size of the planet.

v-offset (vertical offset) is not needed and therefore equal to 0.

blur marks the amount of blur on the shadow, the higher the number, the higher the blur. I played around with this for a while, and found that half of the size of the span would be best suited.

spread marks the size of the shadow. I also tried several different values for this, and finally settled for 1/10 of the span size to be best suited.

The color we are using is, naturally, black (#000). The inset property makes the shadow on the inside instead of the outside.

The box-shadow is a little bit different on the Sun, though, as here the intention was only to make a 3d appearance. Therefore, I am using an all-round shadow, slightly thinner:

box-shadow: 0 0 calc(var(--size-sun) / 5) 10px #000 inset;

Also, I am using an additional shadow around the Sun span element, which is used to make the glow effect of the Sun:

    0 0 60px 30px #ffffff,  /* inner white */
    0 0 60px 30px #ff8c00,  /* middle orange */
    0 0 60px 30px #ffff00;  /* outer yellow */

The same principle applies, only here we have multiple shadows combined, which makes for a gradient effect.

Size and Distance (Horizontal Positioning of the Planets)

The size is achieved by setting the height and the width of the span elements to their corresponding „size“ variable, and the horizontal positions are achieved by translation of all the span elements (planets) horizontally for the „distance“ variable (which already includes the diameter of the Sun):

#mercury.planet {
        height: var(--size-mercury);
        width: var(--size-mercury);
        transform: translate(var(--distance-mercury), -50%);

The -50% part of the transform is used to achieve the vertically centered position.

Texture - Spin and Tilt Effects

In order to achieve the spin effect, an infinitely repeated linear translation of the texture element is used – an animation with a final position defined as the only keyframe.

.texture {
        width: 400%;
        height: 100%;

@keyframes spin {
        to {
            background-position: -200% 0;

    #mercury .texture {
        background: url(
        background-size: auto 100%;
        animation: spin var(--rotation-mercury) linear infinite;
        transform: rotateZ(calc(var(--tilt-mercury) * 1rad));
        transform-origin: calc(var(--size-mercury) / 2) calc(var(--size-mercury) / 2);

The (background) texture is translated to the left; a 400% width is used to make sure that we don't „run out“ of texture while it is being translated (we set the translation to 200%, which is half of that); the linear keyword assures a smooth linear transition between the keyframes, and the infinite keyword means that the animation is constantly repeated.

To achieve the tilt effect, we are using a rotateZ transform by using the appropriate global variable; the transform-origin property is making sure that the center of rotation matches the center of the span (planet).

Points of Interest

The Saturn Ring

The Saturn ring is positioned in the same way as all the planets. To make it appear elliptical, I have multiplied the width by 2.5. We are using an additional translation to position it precisely to create a desired effect. (Note that I am also using the same rotateZ as for the planet itself.)

The tricky part is to make it look like a ring circling around the planet – for this, I used radial-gradient for the background – the inner 50% is completely transparent, allowing for the Saturn span to be visible underneath; the rest is white – thus representing the ring.

#saturn.ring {
    height: calc(var(--size-saturn));
    width: calc(var(--size-saturn) * 2.5);
    transform: translate(calc(var(--distance-saturn) - var(--size-saturn) * 0.78), -60%)
                             rotateZ(calc(var(--tilt-saturn) * 1rad));
    background: radial-gradient(transparent 50%, white);
    border-radius: 50%;


  • 2nd January, 2021: Initial version


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Marijan Nikic
User Interface Analyst Raiffeisenbank Austria
Croatia Croatia
I acquired Masters degree in computing science at the Faculty of Electrical Engineering and Computing in Zagreb, Croatia in 2009. Following my studies, I got a job in a Croatian branch of Austrian-based CEE Raiffeisen Bank as an MIS (Management information system) analyst.
I have been working there since 2010, as an IT expert within the Controlling department, maintaining the Oracle's OFSA system, underlying interfaces and databases.
Throughout that time, I have worked with several different technologies, which include SQL & PL/SQL (mostly), postgres, Cognos BI, Apparo, Datastage, ODI, Jenkins, Qlik, ...
I am doing a lot of automation with scripting in batch / shell and VBscript (mostly) - data analysis and processing, automated DB imports and exports, Jenkins automation etc.
Privately, I was mostly doing Windows Forms and Console app tools in Visual Studio, C#.

Comments and Discussions

QuestionPluto? Pin
Marc Clifton8-Jan-21 6:01
mvaMarc Clifton8-Jan-21 6:01 
QuestionHi Pin
Asif 79698145-Jan-21 3:03
MemberAsif 79698145-Jan-21 3:03 
GeneralMy vote of 5 Pin
Eek Ten Bears5-Jan-21 3:36
MemberEek Ten Bears5-Jan-21 3:36 
SuggestionScreenshot Pin
Samuel Teixeira4-Jan-21 7:11
MemberSamuel Teixeira4-Jan-21 7:11 
GeneralMy vote of 5 Pin
Richard MacCutchan4-Jan-21 1:14
mveRichard MacCutchan4-Jan-21 1:14 
GeneralMy vote of 5 Pin
Bill SerGio, The Infomercial King2-Jan-21 11:00
professionalBill SerGio, The Infomercial King2-Jan-21 11:00 
GeneralMy vote of 5 Pin
Bill SerGio, The Infomercial King2-Jan-21 11:00
professionalBill SerGio, The Infomercial King2-Jan-21 11:00 
QuestionFantastic Job!!! Pin
Bill SerGio, The Infomercial King2-Jan-21 10:58
professionalBill SerGio, The Infomercial King2-Jan-21 10:58 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.