Reputation: 8277
I have a CSS animation where by I am trying to get the child element to rotate around the parent element by a certain amount of degrees. But I cannot get it to rotate around the parent origin, nor can I get it to rotate from the correct radius, it seems to rotate around an invisible smaller circle.
Below is the broken animation. How do I fix this?
.center-circle {
top:100px;
left:100px;
width: 180px;
height: 180px;
border:1px solid black;
border-radius: 100%;
position: relative;
}
.quarter-circle {
width:65px;
height:65px;
position: absolute;
top: 0%;
left: 50%;
border:1px solid #F28B46;
border-radius: 100%;
animation: spin-back 2s ease-in-out;
-webkit-transform-origin: 0% 50%;
}
@-webkit-keyframes spin-back {
0% {
transform:rotate(-120deg);
}
100% {
transform:rotate(0deg);
}
}
<div class="center-circle">
<div class="quarter-circle"></div>
</div>
Upvotes: 1
Views: 4560
Reputation: 89780
This orbiting like animation can be achieved by setting the smaller circle outside of the parent circle at start (using top
, left
) and then setting the transform-origin
as parent's radius + smaller circle's radius. This is because the center of rotation should be at the center of the larger circle which is offset by the top-left of the smaller circle by the combined distance of their radii.
When we set the transform-origin
as 0% 50%
, the 50% is half of the smaller circle's height (which is 32.5px) and so the rotation diameter and so the rotation happens around a smaller imaginary circle. Whereas what we actually need is for it to animate around the larger circle and so imaginary's circles radius has to be higher.
.center-circle {
position: relative;
top: 100px;
left: 100px;
width: 180px;
height: 180px;
border: 1px solid black;
border-radius: 100%;
}
.quarter-circle {
position: absolute;
width: 65px;
height: 65px;
top: -32.5px;
left: -32.5px;
border: 1px solid #F28B46;
border-radius: 100%;
transform: rotate(-45deg);
animation: spin-back 2s ease-in-out forwards;
transform-origin: 122.5px 122.5px;
}
@keyframes spin-back {
0% {
transform: rotate(-45deg);
}
100% {
transform: rotate(135deg);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class="center-circle">
<div class="quarter-circle"></div>
</div>
The below snippet is bit more responsive (and in my opinion a bit better) but it still needs hard-coding of the parent's radius into the transform-origin
. In this snippet, the top left of the smaller circle is at a slightly different offset from the parent's center circle (compared to the previous snippet) and hence the transform-origin
calculation is also different.
.center-circle {
position: relative;
top: 100px;
left: 100px;
width: 180px;
height: 180px;
border: 1px solid black;
border-radius: 100%;
}
.quarter-circle {
position: absolute;
width: 80px;
height: 80px;
top: 50%;
left: 0%;
border: 1px solid #F28B46;
border-radius: 100%;
transform: translateX(-100%) translateY(-50%) rotate(0deg);
animation: spin-back 2s ease-in-out forwards;
transform-origin: calc(100% + 90px) 40px; /* 90px is radius of the parent */
}
@keyframes spin-back {
0% {
transform: translateX(-100%) translateY(-50%) rotate(0deg);
}
100% {
transform: translateX(-100%) translateY(-50%) rotate(180deg);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class="center-circle">
<div class="quarter-circle"></div>
</div>
Upvotes: 2