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 id
s 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 id
s 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.
<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.
:root {
--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;
--distance-mercury:525px;
--distance-venus:555px;
--distance-earth:585px;
--distance-mars:635px;
--distance-jupiter:1005px;
--distance-saturn:1435px;
--distance-uranus:2405px;
--distance-neptune:3505px;
--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;
--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:
box-shadow:
0 0 60px 30px #ffffff,
0 0 60px 30px #ff8c00,
0 0 60px 30px #ffff00;
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(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.
#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