Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / CSS

A pure CSS Solar System

5.00/5 (16 votes)
2 Jan 2021CPOL6 min read 23.1K   746  
A webpage representing the Solar system made in pure CSS
This is a web model of solar system made entirely in CSS.

Introduction

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.

Background

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.

HTML
<body>
<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>
</body>

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.

CSS
:root {
        /*sizes*/
        --size-sun:485px;
        --size-earth:21px;
        --size-jupiter:72px;
        --size-neptune:51px;
        --size-mercury:9px;
        --size-venus:21px;
        --size-mars:11px;
        --size-saturn:69px;
        --size-uranus:51px;
        /*distances*/
        --distance-mercury:525px;
        --distance-venus:555px;
        --distance-earth:585px;
        --distance-mars:635px;
        --distance-jupiter:1005px;
        --distance-saturn:1435px;
        --distance-uranus:2405px;
        --distance-neptune:3505px;
        /*rotations*/
        --rotation-sun: 600s;
        --rotation-earth:24s;
        --rotation-jupiter:10s;
        --rotation-neptune:16s;
        --rotation-mercury:1404s;
        --rotation-venus:2808s;
        --rotation-mars:24s;
        --rotation-saturn:11s;
        --rotation-uranus:17s;
        /*tilts*/
        --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).

CSS
.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:

CSS
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:

CSS
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:

CSS
box-shadow:
    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):

CSS
#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.

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

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

    #mercury .texture {
        background: url(https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/
        e0763947-6f42-4d09-944f-c2d6f41c415b/dcaig77-18800e1e-24aa-43e5-9dd0-3dff9bcf8d0c.jpg?
        token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOiIsImlzcyI6InV
        ybjphcHA6Iiwib2JqIjpbW3sicGF0aCI6IlwvZlwvZTA3NjM5NDctNmY0Mi00ZDA5LTk0NGYtYzJkN
        mY0MWM0MTViXC9kY2FpZzc3LTE4ODAwZTFlLTI0YWEtNDNlNS05ZGQwLTNkZmY5YmNmOGQwYy5qcGc
        ifV1dLCJhdWQiOlsidXJuOnNlcnZpY2U6ZmlsZS5kb3dubG9hZCJdfQ.vigtUwmhB5u_KrjxZcgE04
        UH7OoC16HyLTD5pulA4OA);
        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.

CSS
#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%;
}

History

  • 2nd January, 2021: Initial version

License

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