Rotate objects around circle using CSS?
Asked Answered
P

6

14

I'm attempting to have three objects rotating around a circle. So far I've been able to get one object to spin around the circle. I am unable to get more than one without messing up the code. Could anyone advise on the best way to accomplish this? Here is part of the code and a Fiddle. Thanks!

Here is the Demo

.outCircle {
  width: 200px;
  height: 200px;
  background-color: lightblue;
  left: 270px;
  position: absolute;
  top: 50px;
  -moz-border-radius: 100px;
  -webkit-border-radius: 100px;
  border-radius: 100px;
}
.rotate {
  width: 100%;
  height: 100%;
  -webkit-animation: circle 10s infinite linear;
}
.counterrotate {
  width: 50px;
  height: 50px;
  -webkit-animation: ccircle 10s infinite linear;
}
.inner {
  width: 100px;
  height: 100px;
  background: red;
  -moz-border-radius: 50px;
  -webkit-border-radius: 50px;
  border-radius: 100px;
  position: absolute;
  left: 0px;
  top: 0px;
  background-color: red;
  display: block;
}
@-webkit-keyframes circle {
  from {
    -webkit-transform: rotateZ(0deg)
  }
  to {
    -webkit-transform: rotateZ(360deg)
  }
}
@-webkit-keyframes ccircle {
  from {
    -webkit-transform: rotateZ(360deg)
  }
  to {
    -webkit-transform: rotateZ(0deg)
  }
}
<div class="outCircle">
  <div class="rotate">
    <div class="counterrotate">
      <div class="inner">hello
      </div>
    </div>
  </div>
</div>
Pyromancy answered 18/8, 2016 at 14:21 Comment(2)
You don't need the tags for javascript or jquery, since your question mentions neither.Ascogonium
Javascript or Jquery would be optimal here as calculations can get messy - #10152890Milstone
M
22

Jquery solution which works for any number of outer items.

Jquery shamelessly stolen from ThiefMaster♦ and their answer at this Q & A

var radius = 100; // adjust to move out items in and out 
var fields = $('.item'),
  container = $('#container'),
  width = container.width(),
  height = container.height();
var angle = 0,
  step = (2 * Math.PI) / fields.length;
fields.each(function() {
  var x = Math.round(width / 2 + radius * Math.cos(angle) - $(this).width() / 2);
  var y = Math.round(height / 2 + radius * Math.sin(angle) - $(this).height() / 2);
  if (window.console) {
    console.log($(this).text(), x, y);
  }
  $(this).css({
    left: x + 'px',
    top: y + 'px'
  });
  angle += step;
});
body {
  padding: 2em;
}
#container {
  width: 200px;
  height: 200px;
  margin: 10px auto;
  border: 1px solid #000;
  position: relative;
  border-radius: 50%;
  animation: spin 10s linear infinite;
}
.item {
  width: 30px;
  height: 30px;
  line-height: 30px;
  text-align: center;
  border-radius: 50%;
  position: absolute;
  background: #f00;
  animation: spin 10s linear infinite reverse;
}
@keyframes spin {
  100% {
    transform: rotate(1turn);
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
</div>
Milstone answered 18/8, 2016 at 15:20 Comment(3)
thanks for that. But how do you pause the spin animation on hover? If i use the animation state paused on hover. Still the items are reverse rotated. linkGadson
Brilliant & love it @Milstone . Thanks and really appreciate your help. Saved my day.Gadson
This solution to pause the spin animation on hover works on item hovered on but the other items keep rotating in reverse direction. How to pause the spin animation on ALL items whenever a user hovers on ANY item ? I appreciate the helpLaminate
W
9

Here is a more generic idea with less of code where you don't need JS and you only need to apply an animation to the item (not the container). The trick is to make all the elements at the same position and using the same animation then with the delay we can have the needed result:

#container {
  width: 200px;
  height: 200px;
  margin: 40px auto;
  border: 1px solid #000;
  display:grid;
  grid-template-columns:30px;
  grid-template-rows:30px;
  place-content: center;
  border-radius: 50%;
}
.item {
  grid-area:1/1;
  line-height: 30px;
  text-align: center;
  border-radius: 50%;
  background: #f00;
  animation: spin 12s var(--d,0s) linear infinite; /* duration = 12s, numbor of item = 6 so a delay of 12/6 = 2s */
  transform:rotate(0) translate(100px) rotate(0);
}
@keyframes spin {
  100% {
    transform:rotate(1turn) translate(100px) rotate(-1turn);
  }
}
<div id="container">
  <div class="item" style="--d:0s">1</div>
  <div class="item" style="--d:-2s">2</div>
  <div class="item" style="--d:-4s">3</div>
  <div class="item" style="--d:-6s">4</div>
  <div class="item" style="--d:-8s">5</div>
  <div class="item" style="--d:-10s">6</div>
</div>

We can easily scale to any number using some CSS variables:

#container {
  --n:7;   /* number of item */
  --d:12s; /* duration */

  width: 200px;
  height: 200px;
  margin: 40px auto;
  border: 1px solid #000;
  display:grid;
  grid-template-columns:30px;
  grid-template-rows:30px;
  place-content: center;
  border-radius: 50%;
}
.item {
  grid-area:1/1;
  line-height: 30px;
  text-align: center;
  border-radius: 50%;
  background: #f00;
  animation: spin var(--d) linear infinite; 
  transform:rotate(0) translate(100px) rotate(0);
}
@keyframes spin {
  100% {
    transform:rotate(1turn) translate(100px) rotate(-1turn);
  }
}

.item:nth-child(1) {animation-delay:calc(-0*var(--d)/var(--n))}
.item:nth-child(2) {animation-delay:calc(-1*var(--d)/var(--n))}
.item:nth-child(3) {animation-delay:calc(-2*var(--d)/var(--n))}
.item:nth-child(4) {animation-delay:calc(-3*var(--d)/var(--n))}
.item:nth-child(5) {animation-delay:calc(-4*var(--d)/var(--n))}
.item:nth-child(6) {animation-delay:calc(-5*var(--d)/var(--n))}
.item:nth-child(7) {animation-delay:calc(-6*var(--d)/var(--n))}
.item:nth-child(8) {animation-delay:calc(-7*var(--d)/var(--n))}
.item:nth-child(9) {animation-delay:calc(-8*var(--d)/var(--n))}
/*.item:nth-child(N) {animation-delay:calc(-(N - 1)*var(--d)/var(--n))}*/
<div id="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
</div>

<div id="container" style="--n:5;--d:5s">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
</div>

<div id="container" style="--n:9">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
</div>
Wigging answered 23/1, 2021 at 20:0 Comment(0)
H
8

How about this, demo at the bottom with 3 circles:

.outCircle  {
    width: 200px;
    height: 200px;
    background-color: lightblue;
    left: 270px;
    position: absolute;
    top: 50px;
	-moz-border-radius: 100px;
	-webkit-border-radius: 100px;
	border-radius: 100px;
}

.duringTwentyOne {
  -webkit-animation-duration: 21s;
}

.duringTen {
  -webkit-animation-duration: 10s;
}

.duringFour {
  -webkit-animation-duration: 4s;
}

.infinite {
   -webkit-animation-iteration-count: infinite;
}

.linear {
   -webkit-animation-timing-function: linear;
}

.counter {
   width: 50px;
   height: 50px;
   -webkit-animation-duration: inherit;
   -webkit-animation-direction: reverse;
   -webkit-animation-timing-function: inherit;
   -webkit-animation-iteration-count: inherit;
   -webkit-animation-name: inherit;
}

.rotate {
    width: 100%;
    height: 100%;
    -webkit-animation-name: circle;
    position: relative;
    z-index : 10;
    display : block;
}

.second {
  top : -100%;
}

.thirdBigger {
  top : -240%;
  left: -40%;
  width:150%;
  height: 150%;
}
  
.inner {
    width: 100px;
	height: 100px;
	-moz-border-radius: 50px;
	-webkit-border-radius: 50px;
	border-radius: 100px;
    position: absolute;
    left: 0px;
    top: 0px;
    background-color: red;
    display: block;

}

.red {
  	background: red;
}

.green {
  	background: green;
}


@keyframes circle {
    from {-webkit-transform: rotateZ(0deg)}
    to {-webkit-transform: rotateZ(360deg)}
}
<div class="outCircle">
  <div class="rotate linear infinite duringTen">
    <div class="counter">
      <div class="inner">hello
      </div>
    </div>
  </div>
  <div class="second rotate linear infinite duringFour">
    <div class="counter">
      <div class="inner red">bye bye
      </div>
    </div>
  </div>
  <div class="thirdBigger rotate linear infinite duringTwentyOne">
    <div class="counter">
      <div class="inner green">s'up
      </div>
    </div>
  </div>
</div>
Hachman answered 18/8, 2016 at 14:50 Comment(0)
A
3

Not sure if this is what you are after, but you need to position your rotating circles absolutely (so they don't interfere with each other) and then give them their own animation:

For the counter rotation, just make them then minus of what the rotation degrees is and that will keep your text horizontal

.outCircle {
  width: 200px;
  height: 200px;
  background-color: lightblue;
  left: 270px;
  position: absolute;
  top: 50px;
  -moz-border-radius: 100px;
  -webkit-border-radius: 100px;
  border-radius: 100px;
}
.rotate {
  width: 100%;
  height: 100%;
  position: absolute;  /* add this */
}
.counterrotate {
  width: 100px;
  height: 100px;
}

.inner {
  width: 100px;
  height: 100px;
  text-align: center;
  vertical-align: middle;
  background: red;
  border-radius: 100px;
  background-color: red;
  display: table-cell;
}
.anim1 {
  -webkit-animation: circle1 10s infinite linear;
}
.anim1 .counterrotate {
  -webkit-animation: ccircle1 10s infinite linear;
}
.anim2 {
  -webkit-animation: circle2 10s infinite linear;
}
.anim2 .counterrotate {
  -webkit-animation: ccircle2 10s infinite linear;
}
.anim3 {
  -webkit-animation: circle3 10s infinite linear;
}
.anim3 .counterrotate {
  -webkit-animation: ccircle3 10s infinite linear;
}
@-webkit-keyframes circle1 {
  from {
    -webkit-transform: rotateZ(0deg)
  }
  to {
    -webkit-transform: rotateZ(360deg)
  }
}
@-webkit-keyframes ccircle1 {
  from {
    -webkit-transform: rotateZ(0deg)
  }
  to {
    -webkit-transform: rotateZ(-360deg)
  }
}
@-webkit-keyframes circle2 {
  from {
    -webkit-transform: rotateZ(90deg)
  }
  to {
    -webkit-transform: rotateZ(450deg)
  }
}
@-webkit-keyframes ccircle2 {
  from {
    -webkit-transform: rotateZ(-90deg)
  }
  to {
    -webkit-transform: rotateZ(-450deg)
  }
}
@-webkit-keyframes circle3 {
  from {
    -webkit-transform: rotateZ(180deg)
  }
  to {
    -webkit-transform: rotateZ(540deg)
  }
}
@-webkit-keyframes ccircle3 {
  from {
    -webkit-transform: rotateZ(-180deg)
  }
  to {
    -webkit-transform: rotateZ(-540deg)
  }
}
<div class="outCircle">
  <div class="rotate anim1">
    <div class="counterrotate">
      <div class="inner">hello
      </div>
    </div>
  </div>
  <div class="rotate anim2">
    <div class="counterrotate">
      <div class="inner">hello
      </div>
    </div>
  </div>
  <div class="rotate anim3">
    <div class="counterrotate">
      <div class="inner">hello
      </div>
    </div>
  </div>
</div>
Adp answered 18/8, 2016 at 15:0 Comment(3)
nice work. Is there a way to stop all the circle's rotation animation on hover? Let's say i hover on any one of the rotating circle. I assume -webkit-animation-state:paused;Gadson
you should be able to use that (or the non prefixed version: animation-play-state: paused;)Adp
Thanks for that update. Just wondering if add a hyperlink it doesn't work? Here is the Codepen Demo linkGadson
S
0

Use translateX.

See this jsfiddle.

I made the outer circle position: relative and the inner ones position: absolute, so they lie on top of each others mids (which is just for illustration, this is just for positioning the child circles on the same spot; grouping them).

Then, from this center spot, the translateX tells the animation to give it a radius of in this case 100px (which is the radius of the outer circle). There you go.

Split answered 18/8, 2016 at 14:51 Comment(0)
P
0

.circleLink {
  color: #ececec;
  text-transform: uppercase;
  font-size: 24px;
  line-height: 120%;
  position: relative;
  display: inline-block;
  border: 1px solid blue;
  width: 200px;
  height: 200px;
  -moz-box-flex: 0;
  flex: 0 0 270px;
  display: -moz-box;
  display: flex;
  -moz-box-pack: center;
  justify-content: center;
  -moz-box-align: center;
  align-items: center;
  border-radius: 50%;
}

.round>span:first-child {
  position: relative;
  color:blue;
}

.round>span:first-child::before {
  content: "";
  position: absolute;
  width: 100%;
  height: 0;
  border: 1px solid #ececec;
  bottom: -5px;
  background: #ececec;
  border-radius: 10px;
  left: 0;
}

.round>span:nth-child(2) {
  -webkit-transform: rotate(90deg);
  -moz-transform: rotate(90deg);
  transform: rotate(90deg);
}

.circleLink>span:nth-child(2) {
  position: absolute;
  z-index: 1;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
}

.circleLink>span:nth-child(2) span {
  position: absolute;
  top: -webkit-calc(50% - 0.5px);
  top: -moz-calc(50% - .5px);
  top: calc(50% - 0.5px);
  left: 50%;
  z-index: 1;
  width: 50%;
  height: 1px;
  -webkit-transform-origin: left;
  -moz-transform-origin: left;
  transform-origin: left;
  -webkit-animation: linkRotate 5s linear 0s infinite;
  -moz-animation: linkRotate 5s linear 0s infinite;
  animation: linkRotate 5s linear 0s infinite;
  -webkit-animation-play-state: paused;
  -moz-animation-play-state: paused;
  animation-play-state: paused;
}

.circleLink>span:nth-child(2) span:before {
  content: "";
  position: absolute;
  width: 20px;
  height: 20px;
  top: -10px;
  right: -10px;
  background: #42B4EF;
  border-radius: 50%;
}

.circleLink:hover>span:nth-child(2) span {
  -webkit-animation-play-state: running;
  -moz-animation-play-state: running;
  animation-play-state: running;
}

@-webkit-keyframes linkRotate {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg)
  }

  to {
    -webkit-transform: rotate(1turn);
    transform: rotate(1turn)
  }
}

@-moz-keyframes linkRotate {
  0% {
    -moz-transform: rotate(0deg);
    transform: rotate(0deg)
  }

  to {
    -moz-transform: rotate(1turn);
    transform: rotate(1turn)
  }
}

@keyframes linkRotate {
  0% {
    -webkit-transform: rotate(0deg);
    -moz-transform: rotate(0deg);
    transform: rotate(0deg)
  }

  to {
    -webkit-transform: rotate(1turn);
    -moz-transform: rotate(1turn);
    transform: rotate(1turn)
  }
}
<div class="round">
 <a href="#" class="circleLink">
  <span>Loram</span>
   <span><span></span></span>
    </a>
</div>
Periphrastic answered 21/11, 2022 at 11:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.