3

I'm trying to render a "solar system" diagram only with css, the concentric circles are easy to do with css border-radius, border and some transforms but I'm trying to find a way to have the little "planets" adhere to the "orbits" or colored borders. There has to be a more precise way to achieve this

If you look at this image you will see what I'm trying to do:

enter image description here

And how it currently looks, sorry for inline css...

enter image description here

<div style="width:100%; height:100vh; padding:0px; background-color:white; display:flex; flex-direction:column; position:relative; align-items:flex-end;">
        <div style="width:250px; height:250px; position:absolute; border-radius:50%; background-color:red; top:50%; transform:translateY(-50%) translateX(50%);  right:0px"></div>
        <div style="width:450px; height:450px; position:absolute; border-radius:50%; border:2px solid red; top:50%; transform:translateY(-50%) translateX(50%);  right:0px"></div>
        <div style="width:650px; height:650px; position:absolute; border-radius:50%; border:2px solid red; top:50%; transform:translateY(-50%) translateX(50%);  right:0px"></div>
        <div style="width:850px; height:850px; position:absolute; border-radius:50%; border:2px solid red; top:50%; transform:translateY(-50%) translateX(50%);  right:0px"></div>
        <div style="position:absolute; height:70%; width:100px; top:50%; transform:translateY(-50%); right:15%; outline:1px solid red;">
            <div style="width:25px; height:25px; border-radius:50%; border:1px solid red; position:absolute; top:0px; left:0px;"></div>
            <div style="width:25px; height:25px; border-radius:50%; border:1px solid red; position:absolute; transform:translateY(-50%); top:50%; right:100%;"></div>
            <div style="width:25px; height:25px; border-radius:50%; border:1px solid red; position:absolute; bottom:0px; left:0px;"></div>
        </div>
        <div style="position:absolute; height:80%; width:100px; top:50%; transform:translateY(-50%); right:55%; outline:1px solid red;">
            <div style="width:50px; height:50px; border-radius:50%; border:1px solid red; position:absolute; top:0px; left:0px;"></div>
            <div style="width:50px; height:50px; border-radius:50%; border:1px solid red; position:absolute; transform:translateY(-50%); top:50%; right:100%;"></div>
            <div style="width:50px; height:50px; border-radius:50%; border:1px solid red; position:absolute; bottom:0px; left:0px;"></div>
        </div>
    </div>
dippas
  • 58,591
  • 15
  • 114
  • 126
gabogabans
  • 3,035
  • 5
  • 33
  • 81
  • 1
    If the radius of your orbiting planet is r and the diameter of the orbit circle is d, make a box whose width and height are equal to (d + r/2). Place your planet inside the box at x: 50%, y: 0, and then just rotate the outer box. The box should be centered over the circles. – Liftoff Oct 22 '19 at 23:16
  • 1
    Example fiddle to follow-up my last comment: https://jsfiddle.net/tyLg48sx/ – Liftoff Oct 22 '19 at 23:24

2 Answers2

4

Since it's about circles you can rely on rotation where you simply need to know the distance from the center (the radius). You can also optimize the concentric circles by using less elements.

Here is an example where I will be using CSS variables to easily control each element. Note that the order of transformation is important (we center using translate, we rotate, then we translate again)

.orbit{
  width:150px;
  height:150px;
  padding:30px;
  border-radius:50%;
  background:red content-box;
  border:1px solid red; /*1st orbit at 105px (30px + 150px/2) */
  margin:auto;
  position:relative;
}
/* 2nd at 135px  */
.orbit:before,
.orbit:after{
   content:"";
   position:absolute;
   top: var(--o,-30px);
   bottom: var(--o,-30px);
   left: var(--o,-30px);
   right: var(--o,-30px);
   border:inherit;
   border-radius:inherit
}
/* 3rd orbit at 165px*/
.orbit:after {
  --o:-60px;
}
.orbit span {
  position:absolute;
  z-index:1;
  height:20px;
  width:20px;
  background:blue;
  border-radius:inherit;
  top:50%;
  left:50%;
  transform:translate(-50%,-50%) rotate(var(--r,0deg)) translateX(var(--d,0px));
}
body {
  margin:0;
  height:100vh;
  display:flex;
}
<div class="orbit">
    <span style="--d:105px;--r:80deg"></span>
    <span style="--d:105px;--r:120deg"></span>
    <span style="--d:105px;--r:-80deg"></span>
    <span style="--d:135px;--r:80deg;height:30px;width:30px;background:green"></span>
    <span style="--d:135px;--r:-90deg;height:30px;width:30px;background:green"></span>
    <span style="--d:165px;--r:-45deg"></span>
    <span style="--d:165px;--r:200deg;height:50px;width:50px;background:purple"></span>
</div>

Another more optimized code without transparency:

.orbit{
  width:150px;
  height:150px;
  padding:30px;
  border-radius:50%;
  background:red content-box;
  border:1px solid red;
  box-shadow:
    0 0 0 29px #fff,
    0 0 0 30px red,
    0 0 0 59px #fff,
    0 0 0 60px red;
  margin:auto;
  position:relative;
}

.orbit span {
  position:absolute;
  height:20px;
  width:20px;
  background:blue;
  border-radius:inherit;
  top:50%;
  left:50%;
  transform:translate(-50%,-50%) rotate(var(--r,0deg)) translateX(var(--d,0px));
}
body {
  margin:0;
  height:100vh;
  display:flex;
}
<div class="orbit">
    <span style="--d:105px;--r:80deg"></span>
    <span style="--d:105px;--r:120deg"></span>
    <span style="--d:105px;--r:-80deg"></span>
    <span style="--d:135px;--r:80deg;height:30px;width:30px;background:green"></span>
    <span style="--d:135px;--r:-90deg;height:30px;width:30px;background:green"></span>
    <span style="--d:165px;--r:-45deg"></span>
    <span style="--d:165px;--r:200deg;height:50px;width:50px;background:purple"></span>
</div>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
0

you may also draw the circle from shadows, and rotate elements from one far side, so you have to mind about its width only :

example :

html {
  display: flex;
  min-height: 100vh;
}
body {
  margin: auto;
}
ul,
li,
span {
  margin: 0;
  padding: 0;
}
li {
  position: absolute;
  color: gray;
  list-style-position: inside;
  font-size: 2.5vw;
  top: 0.2em;
  right:0.0em;
  line-height: 0;
  height:0;
  white-space: nowrap;
  transform-origin: center right;
  margin: -0.4vw 0;
}
span {
  position: absolute;
  color: black;
  transform: translate(-70%, 1.5em) rotate(0);
  font-size: 0.5em;
  color: tomato;
}

body {
  position: relative;
  width:0.4em;
  height:0.4em;
  border-radius: 50%;
  background:orange;
  box-shadow: 
  inset 0 0 0 5px orange,
    0 0 0 3vw     orange, 
    0 0 1vw 3vw   orange, 
    0 0 0 3vw     #333,
    0 0 0 6vw     #444, 
    0 0 0 6vw     blue, 
    0 0 0 6.2vw   blue,
    
    0 0 0 6.2vw   #333,
    0 0 0 7.5vw   #333, 
    0 0 0 7.5vw   blue, 
    0 0 0 7.7vw   blue, 
    
    0 0 0 7.75vw  #333,
    0 0 0 8.7vw   #222, 
    0 0 0 9.5vw   #222, 
    0 0 0 9.55vw  green, 
    0 0 0 9.7vw   green,
    
    0 0 0 9.75vw  #222, 
    0 0 0 11.5vw  #111,
    0 0 0 11.5vw  blue,
    0 0 0 11.7vw  blue,
    
    0 0 0 11.75vw  #222, 
    0 0 0 15.2vw  #111,
    0 0 0 15.2vw  blue,
    0 0 0 15.4vw  blue,
    
    0 0 0 15.45vw #222, 
    0 0 0 17.4vw  #111,
    0 0 0 17.4vw  blue,
    0 0 0 17.6vw  blue,
    
    0 0 0 17.65vw #222, 
    0 0 0 19.3vw  #111,
    0 0 0 19.3vw  blue,
    0 0 0 19.5vw  blue,
    
    0 0 0 19.55vw #222, 
    0 0 0 22.3vw  #111,
    0 0 0 22.3vw  blue,
    0 0 0 22.5vw  blue,
    
    0 0 0 100vw ;
}
li:nth-child(1) {
  width: 6.9vw;
  animation: rotate 1s -1s linear infinite ;
}
li:nth-child(1) span {
  animation: rotateName 1s -1s linear infinite ;
}
li:nth-child(2) {
  color:brown;
  width: 8.4vw;
  animation: rotate 1.5s -1.5s linear infinite ;
}
li:nth-child(2) span {
  animation: rotateName  1.5s -1.5s  linear infinite ;
}

li:nth-child(3) {
  color:rgb(0, 120, 212);
  width: 10.6vw;
  animation: rotate 2s 1s linear infinite ;
}
li:nth-child(3) span {
  animation: rotateName 2s  1s linear infinite ;
}

li:nth-child(4) {
  color:red;
  width: 12.5vw;
  animation: rotate 2.5s -2.5s linear infinite ;
}
li:nth-child(4) span {
  animation: rotateName  2.5s -2.5s  linear infinite ;
}
li:nth-child(5) {
  color:gold;
  width: 15.5vw;
  animation: rotate 3s -3s linear infinite ;
}
li:nth-child(5) span {
  animation: rotateName  3s -3s  linear infinite ;
}
li:nth-child(6) {
  color:turquoise;
  width: 17.5vw;
  animation: rotate 3.5s -3.5s linear infinite ;
}
li:nth-child(6) span {
  animation: rotateName  3.5s -3.5s  linear infinite ;
}
li:nth-child(7) {
  color:darkgreen;
  width: 19.5vw;
  animation: rotate 4s -4s linear infinite ;
}
li:nth-child(7) span {
  animation: rotateName  4s -4s  linear infinite ;
}
li:nth-child(8) {
  color:cyan;
  width: 22.5vw;
  animation: rotate 4.5s -4.5s linear infinite ;
}
li:nth-child(8) span {
  animation: rotateName  4.5s -4.5s  linear infinite ;
}

body:before {
  content:'SUN';
  position:absolute;
  font-size:1.5vw;
  transform:translate(-50%,-0.5em);
  color:red;text-shadow: 0 0 0.2em gold,0 0 0.2em gold,0 0 0.2em gold,0 0 0.2em gold,0 0 0.2em gold,0 0 0.2em gold,0 0 0.2em gold,0 0 0.2em gold,0 0 0.2em gold,0 0 0.2em gold,0 0 0.2em gold,0 0 0.2em gold,0 0 0.2em gold ;
}

 
@keyframes rotate {
  100% {transform:rotate(360deg)}
}
@keyframes rotateName {
   100%{transform: translate(-70%, 1.5em) rotate(-360deg)}
}
<ul>
  <li><span>Mercury</span></li>
  <li><span>Venus</span></li>
  <li><span>Earth</span></li>
  <li><span>Mars</span></li>
  <li><span>Jupiter</span></li>
  <li><span>Saturne</span></li>
  <li><span>Uranus</span></li>
  <li><span>Neptune</span></li>
</ul>

Inspired from How to set an animation to have elements moving around a circle? ,the third snippet shows visually how it works.

G-Cyrillus
  • 101,410
  • 14
  • 105
  • 129