Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Achieving a planet with rings effect with CSS

I am trying to make a planet with rings, like this photo

enter image description here

I am currently doing it in what seems to be a very dirty way. The ring (ellipse) is a div with no background and a black border rotated, and I achieve the effect of the ring going behind the planet by adding another half of a red circle on top.

Here is the JSFiddle and below is a snippet demo.

.elipse {
  width: 300px;
  height: 105px;
  background: none;
  border-radius: 50%;
  -ms-transform: rotate(40deg);  /* IE 9 */
  -webkit-transform: rotate(40deg);  /* Safari */
  transform: rotate(40deg);
  position: absolute;
  left: 45px;
  top: 45px;
  border: 5px solid black;
}
.full-planet {
  height: 170px;
  width: 170px;
  border-radius: 170px 170px 170px 170px;
  -moz-border-radius: 170px 170px 170px 170px;
  -webkit-border-radius: 170px 170px 170px 170px;
  position: absolute;
  left: 120px;
  top: 20px;
  background: red;
}
.half-planet {
  height: 85px;
  width: 170px;
  border-radius: 170px 170px 0 0;
  -moz-border-radius: 170px 170px 0 0;
  -webkit-border-radius: 170px 170px 0 0;
  -ms-transform: rotate(40deg);  /* IE 9 */
  -webkit-transform: rotate(40deg);  /* Safari */
  transform: rotate(40deg);
  position: absolute;
  left: 147px;
  top: 30px;
  background: red;
}
.cont {
  padding-left: 100px;
  padding-top: 100px;
  position: relative;
  width: 0;
  height: 0;
}
<div class='container'>
  <div class="full-planet"></div>
  <div class='elipse'></div>
  <div class="half-planet"></div>
</div>

It is very troublesome to adjust the parameters to obtain a nice alignment. If I have to change one parameter, for example, I have to change almost every other in order to keep things aligned. Is there a way of doing this so that I don't need to constantly adjust the parameters based on my vision? I feel like there is a cleaner way of doing this.

like image 621
Gabriel Ilharco Avatar asked Dec 25 '22 09:12

Gabriel Ilharco


2 Answers

Using SVG:

I would generally recommend using SVG for such effects/shapes because drawing arcs is far easier to do with SVG. The z-index of SVG elements depend on the order in which they appear in the DOM. So it is also easier to control their order. SVGs are also responsive by nature.

You can find more information about how to draw elliptical arcs with SVG in this page.

svg {
  width: 200px;
  height: 200px;
  margin: 20px;
}
<svg viewBox='0 0 130 130'>
  <path d='M0,78 a65,25 0 1 1 102.5,45' stroke='black' stroke-width='2' fill='transparent' transform='rotate(45,100,100)' />
  <circle cx='65' cy='65' r='45' fill='red' />
  <path d='M0,78 a65,25 0 1 0 102.5,45' stroke='black' stroke-width='2' fill='transparent' transform='rotate(45,100,100)' />
</svg>

Using CSS:

With CSS it is going to be difficult to create that effect and you would more than likely require an extra element to produce the effect. In your code, you had placed an extra half-circle on top to make part of the ring go behind whereas in my snippet below, I had used an extra element with lower z-index for one part of the ring. However, I have used percentages for almost all settings and so there would not be much need to change a lot of paramaters when one changes. As you can see in the snippet output (hover on the shape), it is pretty responsive too.

.wrapper {
  position: relative;
  height: 200px;
  width: 200px;
}
.ring { /* produces the front part of the ring */
  position: absolute;
  height: 100%;
  width: 45%;
  left: 27.5%; /* half of 100% - width (to position in center) */
  border: 2px solid;
  border-color: black transparent black black;
  border-radius: 50%;
  transform: rotate(-45deg);
  z-index: 2; /* brings it forward */
}
.ring-behind { /* produces the part that goes behind */
  position: absolute;
  height: 100%;
  width: 45%;
  left: 27.5%; /* half of 100% - width (to position in center) */
  border: 2px solid;
  border-color: transparent black transparent transparent;
  border-radius: 50%;
  transform: rotate(-45deg);
  z-index: -1; /* sends it behind */
}
.planet {
  position: absolute;
  height: 75%;
  width: 75%;
  top: 12.5%; /* half of 100% - height (to position in middle) */
  left: 12.5%; /* half of 100% - width (to position in center) */
  border-radius: 50%;
  background: red;
  z-index: 1; /* above the back part of the ring but below the front */
}

/* just for demo */

.wrapper {
  transition: all 1s;
}
.wrapper:hover {
  height: 300px;
  width: 300px;
}
<div class='wrapper'>
  <div class='ring'></div>
  <div class='ring-behind'></div>
  <div class='planet'></div>
</div>
like image 85
Harry Avatar answered Dec 27 '22 02:12

Harry


Some day things will be easier ...

CSS solution, as it should be (one div for the planet and one for the ring, responsive markup, and so on... but working only in webkit)

.planet {
  width: 330px;
  height: 330px;
  background-color: lightgreen;
  border-radius: 50%;
  margin: 100px;
  position: relative;
  perspective: 1000px;
  transform-style: preserve-3d;
  box-shadow: inset green -20px -20px 70px;
}

.ring {
  width: 150%;
  height: 150%;
  border: solid 10px red;
  border-radius: 50%;
  top: -25%; 
  left: -25%; 
  position: absolute;
  transform: rotate3d(0.8, 0.2, 0, 75deg); 
  box-sizing: border-box;
}
<div class="planet">
<div class="ring"></div>
</div>
like image 23
vals Avatar answered Dec 27 '22 03:12

vals