I am attempting to "orbit" two separate divs in circular motion around a center, however I am having trouble getting the two divs to follow the same circular path in my CSS animation.
.container {
width: 500px;
height: 500px;
display: flex;
align-items: center;
justify-content: center;
}
.box {
background-color: pink;
width: 100px;
height: 100px;
animation: battle 6s linear infinite;
position: absolute;
margin: 10px;
}
#keyframes battle {
from {
transform: rotate(0deg) translateX(150px) rotate(0deg);
}
to {
transform: rotate(360deg) translateX(150px) rotate(-360deg);
}
}
<div class="container">
<div class="box">
</div>
<div class="box">
</div>
</div>
Jsfiddle
Let your parent element be the guide;
When the goal is to rotate in a consistent spacing around a center (as opposed to say an "elliptical orbit" that is more of an oval pattern) than the easiest technique is to provide a parent to set a consistent boundary and attach children within it to use its position as their animation path. The goal is to just supply an illusion of individual elements orbiting in sync when in reality just one is rotating with its default transform-origin of center acting as the guide for the children "orbiting" within it.
In our case we took a parent whose equal circumference is roughly the size of the "orbit desired" and we gave it a border-radius of 50% to create a circle. This makes no point on the element less than or greater distance from the other. We make it a position: relative element so that we can apply position: absolute to any children of it. In this example we use pseudo elements but they could just as easily be additional DOM node elements like divs.
By fixing our children to specific points on the parent we create the equal distance from the X/Y of the parent's transform-origin center we desire and apply the rotate transform to spin the parent. However if we only did that then the children would also follow that path and not keep vertical (as it is assumed is desired) so we simply re-use the same animation applied to the parent but in reverse to offset its rotation. The result is a parent element spinning one direction, and the children in the other to create the effect seen in the example. Hope this helps!
#rotator {
position: relative;
width: 7rem;
height: 7rem;
animation: rotations 6s linear infinite;
border: 1px orange dashed;
border-radius: 50%;
margin: 3rem;
}
#rotator:before, #rotator:after {
position: absolute;
content: '';
display: block;
height: 3rem;
width: 3rem;
animation: inherit;
animation-direction: reverse;
}
#rotator:before {
background-color: red;
top: -.25rem;
left: -.25rem;
}
#rotator:after {
background-color: green;
bottom: -.25rem;
right: -.25rem;
}
#keyframes rotations {
to { transform: rotate(360deg) }
}
<div id="rotator"></div>
Something I did many years ago might be close to what you are looking for:
// Base
body {
background: #252525;
}
// Keyframes
#keyframes rotateClockwise {
100% {
transform: rotate(360deg);
}
}
#keyframes rotateCounterClockwise {
100% {
transform: rotate(-360deg);
}
}
// Ring
.ring {
position: relative;
left: 50%;
top: 50px;
margin-left: -100px;
height: 200px;
width: 200px;
border: 10px solid #666;
border-radius: 50%;
}
// Dots
.dot {
position: absolute;
height: 250px;
width: 40px;
top: -25px;
left: 50%;
margin-left: -20px;
&:before {
display: block;
content: '';
height: 40px;
width: 40px;
border-radius: 50%;
box-shadow: 0 2px 3px rgba(0,0,0,.1);
}
}
.dot--one {
animation: rotateClockwise 4s linear infinite;
&:before {
background: #e6a933;
}
}
.dot--two {
animation: rotateCounterClockwise 2s linear infinite;
&:before {
background: #e63348;
}
}
.dot--three {
animation: rotateClockwise 7s linear infinite;
&:before {
background: #70b942;
}
}
.dot--four {
animation: rotateCounterClockwise 12s linear infinite;
&:before {
background: #009ee3;
}
}
<div class="ring">
<div class="dot dot--one"></div>
<div class="dot dot--two"></div>
<div class="dot dot--three"></div>
<div class="dot dot--four"></div>
</div>
https://codepen.io/seanstopnik/pen/93f9cbcbcf9b38684bfc75f38c9c4db3
Related
I tried making a rotating square that would turn into an oval while rotating 180 degrees, the issue I encountered is that as the square rotates it moves to the left so that the top-left corner always stays in the same. Visualization of the problem. I think it's caused by the fact that my animation changes the width of the square:
`#keyframes squarestuff {
50% {
transform: rotate(180deg);
width: 5rem;
border-radius: 50%;
}`
try adding this
#keyframes squarestuff {
50% {
transform: rotate(180deg);
width: 5rem;
border-radius: 50%;
transform-origin:center center;
}
Since it transform the center and rotate about new center.
make the width of div contain the square as width of square if still there is problem
This is it:
https://jsfiddle.net/0pz1tv7q/
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
div {
height: 100px;
width: 100px;
border: 5px solid black;
background: red;
position: absolute;
animation: mymove 5s;
animation-fill-mode: forwards;
}
#keyframes mymove {
100% {
transform: rotate(180deg);
width: 25%;
border-radius: 50%;
}
}
</style>
</head>
<body>
<h2>Square CSS</h2>
<div></div>
</body>
</html>
Assuming you want the center of the oval to remain in the center of the 'square' (i.e not to move) then you can use a transform scale instead of changing the width.
This snippet rotates the square with its center always in the same place and adds the oval as a pseudo element so you see what is happening and that the center does not move:
div {
width: 10rem;
height: 10rem;
background-color: magenta;
animation: squarestuff 5s linear infinite;
transform-origin: center center;
position: relative;
}
#keyframes squarestuff {
50% {
transform: rotate(180deg);
}
}
div::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(1, 1);
background: blue;
width: 10rem;
height: 10rem;
animation: square2oval 5s linear infinite;
z-index: 1;
display: inline-block;
}
#keyframes square2oval {
50% {
transform: translate(-50%, -50%) scale(0.5, 1);
border-radius: 50%;
}
}
<div></div>
I have a round breathing click me button beneath, here I am using #keyframes to animate the button breathing - so far all good!
But as you can tell the click me text is shaking during the breathing animation.
Is there a way to avoid this from happening?
.centered {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%)
}
button.circle {
--startSize: 65vh;
--endSize: 85vh;
width: var(--startSize);
height: var(--startSize);
background: teal;
border-radius: 100%;
animation-name: breathe;
animation-play-state: running;
animation-duration: 4.5s;
animation-iteration-count: infinite;
animation-direction: alternate;
border: none;
}
#keyframes breathe {
0% {
width: var(--startSize);
height: var(--startSize);
}
25% {
width: var(--startSize);
height: var(--startSize);
}
75% {
width: var(--endSize);
height: var(--endSize);
}
100% {
width: var(--endSize);
height: var(--endSize);
}
}
<button class="circle centered">Click me</button>
Perhaps a better way to animate this would be to use transform: scale(...) on the ::after pseudo-element. Using this method we get the following benefits:
The animation no longer affects document flow1. When animating, prefer transform and opacity over properties like width or height. The latter will affect the elements around it (the document flow). Transforms are purely visual - they have no affect on other elements in terms of placement, which means improved performance.
The text is separate from the animation which means no more shakiness.
.centered {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%)
}
button.circle {
width: 65vh;
height: 65vh;
border: 0;
background-color: transparent;
}
button.circle::after {
z-index: -1;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
content: '';
display: block;
background: teal;
border-radius: 100%;
animation: breathe 4.5s ease infinite alternate running;
}
#keyframes breathe {
from { transform: scale(1); }
to { transform: scale(1.4); }
}
<button class="circle centered">Click me</button>
Note: Browser support for this method
1. I realize the button is centered and positioned absolute which means it isn't affecting document flow to begin with. That said, this method of animating with transforms is more flexible for either scenario.
Problem is with the transform property you're using to centre the button. I've put a JSFiddle together using the grid property to centre the button horizontally and vertically, which stops the text shaking.
body,
html {
height: 100%;
display: grid;
}
.circle-outer {
margin: auto;
text-align: center;
}
button.circle {
--startSize: 65vh;
--endSize: 85vh;
width: var(--startSize);
height: var(--startSize);
background: teal;
border-radius: 100%;
animation-name: breathe;
animation-play-state: running;
animation-duration: 4.5s;
animation-iteration-count: infinite;
animation-direction: alternate;
border: none;
}
#keyframes breathe {
0% {
width: var(--startSize);
height: var(--startSize);
}
25% {
width: var(--startSize);
height: var(--startSize);
}
75% {
width: var(--endSize);
height: var(--endSize);
}
100% {
width: var(--endSize);
height: var(--endSize);
}
}
<div class="circle-outer">
<button class="circle">Click me</button>
</div>
And a working example:
https://jsfiddle.net/WebDevelopWolf/7ujm2L5v/11/
If a div is nested inside of another, can the nested div ignore the hover of the parent. Here's an example
.Box {
width: 50px;
height: 50px;
background: red;
}
.Circle {
width: 20px;
height: 20px;
background: blue;
border-radius: 20px;
}
.Box:hover {
animation: expand .5s normal forwards;
}
#keyframes expand {
0% {
transform: scale(1);
}
100% {
transform: scale(1.6);
}
}
<div class="Box">
<div class="Circle"></div>
</div>
In this example would there be a way to make the Box expand but not the Circle
Technically the parent hover event doesn't get applied to the child.
But in your case the child is still effected, because you're scaling the parent. And thus everything inside of the parent is being scaled too.
In order to counter the scaling of the nested div, you can apply a reverse scaling effect when the parent div is hovered.
.Box{
width: 50px;
height: 50px;
background: red;
}
.Circle{
width: 20px;
height: 20px;
background: blue;
border-radius: 20px;
}
.Box:hover{
animation: expand .5s normal forwards;
}
.Box:hover .Circle {
animation: contract .5s normal forwards;
}
#keyframes expand {
0% {
transform: scale(1);
}
100% {
transform: scale(1.6);
}
}
#keyframes contract {
0% {
transform: scale(1);
}
100% {
transform: scale(0.625); /* 1 / 1.6 */
}
}
<div class="Box">
<div class="Circle"></div>
</div>
Because you are scaling the parent, everything inside it will be impacted. An alternative solution is to have a different sibling to the circle and apply the animation on that.
CSS:
.Box {
width: 50px;
height: 50px;
background: red;
}
.Circle {
width: 20px;
height: 20px;
background: blue;
border-radius: 20px;
position: absolute;
top: 10px;
left: 10px;
}
.Container {
position: relative;
}
.Box:hover {
animation: expand .5s normal forwards;
}
#keyframes expand {
0% {
transform: scale(1);
}
100% {
transform: scale(1.6);
}
}
HTML:
<div class="Container">
<div class="Box">
</div>
<div class="Circle"></div>
</div>
Demo: http://jsfiddle.net/lotusgodkk/GCu2D/2157/
Here, the circle is positioned so that it's position is not affected by the box
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am playing around with this code on codepen and I am trying to place text, under the animated circle and centered in the viewport, but I cannot seem to find a way to do it. I have set background: yellow; on the text for visibility.
If you know why the solution works, it would be immensely helpful if you could explain it here for me to understand/learn.
Try this: https://codepen.io/Lansana/pen/ezvVYR
HTML:
<div class="spinner-wrapper">
<div class='spinner'>
<div class='quadrant'></div>
<div class='quadrant'></div>
<div class='quadrant'></div>
<div class='quadrant'></div>
</div>
<div class='text'>test</div>
</div>
CSS:
html,
body {
height: 90%;
}
body {
background: #c2c2c2;
display: flex;
align-items: center;
justify-content: center;
}
.text {
background: yellow;
text-align: center;
}
.spinner-wrapper {
width: auto;
height: auto;
position: relative;
}
.spinner {
width: 300px;
height: 300px;
min-width: 300px;
position: relative;
animation: spin 60s linear infinite;
//border-radius: 300px;
.quadrant {
position: absolute;
top: 0%;
left: 0%;
width: 100%;
height: 100%;
//z-index: 10;
mix-blend-mode: multiply;
//opacity: .5;
&:after {
content: "";
color: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: 100%;
}
&:nth-child(1) {
animation: slide_horiz_neg 12s linear alternate infinite;
&:after {
//mix-blend-mode: multiply;
//opacity: .5;
background: cyan;
}
}
&:nth-child(2) {
animation: slide_vert_neg 8s linear alternate infinite;
&:after {
//mix-blend-mode: multiply;
//opacity: .5;
background: yellow;
}
}
&:nth-child(3) {
animation: slide_horiz_pos 10s linear alternate infinite;
&:after {
//mix-blend-mode: multiply;
//opacity: .5;
background: magenta;
}
}
/* &:nth-child(4) {
// animation: slide_vert_pos 3.5s linear alternate infinite;
&:after {
mix-blend-mode: normal;
//opacity: .5;
background: #000000;
}
} */
}
}
#keyframes spin {
to {
transform: rotate(360deg);
}
}
#keyframes slide_vert_pos {
0% {
transform: translateY(0%);
}
100% {
transform: translateY(1%);
}
}
#keyframes slide_vert_neg {
0% {
transform: translateY(0%);
}
100% {
transform: translateY(-1%);
}
}
#keyframes slide_horiz_pos {
0% {
transform: translateX(0%);
}
100% {
transform: translateX(1%);
}
}
#keyframes slide_horiz_neg {
0% {
transform: translateX(0%);
}
100% {
transform: translateX(-1%);
}
}
I created a wrapper, which contains your spinner and the text.
The wrapper has an auto height/width, based on it's child elements.
The text can be positioned any way you want within that wrapper, and it is not effected at all by the spinner except for the order in which the two are placed within the dom.
if you use flex, then apply it on HTML so body can shrink on content. margin-left:-50%; will be efficient and can be used to center one element.
For vertical-align, you may use (either) display : inline-block/inline-table + vertical-align:middle in order to center 2 elements being side by sides.
basicly, your CSS template can become
html {
height: 90%;
background: #c2c2c2;
display: flex;
align-items: center;
justify-content: center;
}
body {margin:0;}
.text {
background: yellow;
display: inline-table;/* or inline-block to vertical align */
vertical-align: middle;
margin-left: -50%;/* body flex-child takes width of content, not window ;) */
position: relative;/* bring it up front , add z-index too if needed */
}
.spinner {
display: inline-block;/* not a flex-child anymore & float doesn't allow vertical-align */
vertical-align: middle;/* says itself */
width: 300px;
height: 300px;
min-width: 300px;
position: relative;
animation: spin 60s linear infinite;
}
... and render -> https://codepen.io/anon/pen/qNrxPQ
Modified your code you can have look at codepen
https://codepen.io/anon/pen/KMWZOM
HTML
<div class="wrapper">
<div class='spinner'>
<div class='quadrant'></div>
<div class='quadrant'></div>
<div class='quadrant'></div>
<div class='quadrant'></div>
</div>
<div class='text'>test</div>
</div>
CSS
html,
body {
height: 90%;
}
.wrapper{
position:relative;
margin:0 auto;
}
body {
background: #c2c2c2;
display: flex;
align-items: center;
justify-content: center;
}
.text {
position: absolute;
background: yellow;
top:50%;
left:50%;
}
.spinner {
width: 300px;
height: 300px;
min-width: 300px;
position: relative;
animation: spin 60s linear infinite;
//border-radius: 300px;
.quadrant {
position: absolute;
top: 0%;
left: 0%;
width: 100%;
height: 100%;
//z-index: 10;
mix-blend-mode: multiply;
//opacity: .5;
&:after {
content: "";
color: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: 100%;
}
&:nth-child(1) {
animation: slide_horiz_neg 12s linear alternate infinite;
&:after {
//mix-blend-mode: multiply;
//opacity: .5;
background: cyan;
}
}
&:nth-child(2) {
animation: slide_vert_neg 8s linear alternate infinite;
&:after {
//mix-blend-mode: multiply;
//opacity: .5;
background: yellow;
}
}
&:nth-child(3) {
animation: slide_horiz_pos 10s linear alternate infinite;
&:after {
//mix-blend-mode: multiply;
//opacity: .5;
background: magenta;
}
}
/* &:nth-child(4) {
// animation: slide_vert_pos 3.5s linear alternate infinite;
&:after {
mix-blend-mode: normal;
//opacity: .5;
background: #000000;
}
} */
}
}
#keyframes spin {
to {
transform: rotate(360deg);
}
}
#keyframes slide_vert_pos {
0% {
transform: translateY(0%);
}
100% {
transform: translateY(1%);
}
}
#keyframes slide_vert_neg {
0% {
transform: translateY(0%);
}
100% {
transform: translateY(-1%);
}
}
#keyframes slide_horiz_pos {
0% {
transform: translateX(0%);
}
100% {
transform: translateX(1%);
}
}
#keyframes slide_horiz_neg {
0% {
transform: translateX(0%);
}
100% {
transform: translateX(-1%);
}
}
You can also try this:
.text {
position: relative;
background: yellow;
right: 150px;
top: 200px;
}
Since your spinner's circumference was 300px, to center it directly below, I divided it by half and assigned that position to the text to center it as well as any number above 150px in order to settle below the circle. Remember, these positions act inverted. Right moves it left and so on.
I needed spinning effect on hover of that square, what i can get is written below.
HTML
<div class="mainSquare">
<div class="firstInnerSquare">
<div class="lastInnerSquare">
Hello
</div>
</div>
</div>
CSS
.mainSquare{
width:160px;
height:160px;
background:black;
margin: 50px auto;
padding:25px;
}
.firstInnerSquare{
width:110px;
height:110px;
background:red;
padding:25px;
}
.lastInnerSquare{
text-align:center;
width:110px;
padding: 46px 0px;
background:white;
}
Fiddle
Hope to get help.
You can do this by using a single element and two pseudos. Make the 2 pseudo elements larger than the container element, position them behind the container and add a rotate animation to them.
Note: This is only a base sample that would help you get started. I would leave the fine tuning part for you to handle. You can read more about the CSS animation properties in this MDN page.
.shape {
position: relative; /* used to position the pseudos relative to the parent */
height: 100px;
width: 100px;
background: white;
border: 1px solid;
margin: 100px; /* required because children are larger than parent */
}
.shape:after,
.shape:before {
position: absolute;
content: '';
}
.shape:before {
height: 125%; /* make one pseudo 25% larger than parent */
width: 125%;
top: -12.5%; /* 25/2 to make sure its center is same as the parent's */
left: -12.5%; /* 25/2 to make sure its center is same as the parent's */
background: red;
z-index: -1; /* send it behind the parent */
}
.shape:after {
height: 150%; /* make this pseudo larger than the parent and the other pseudo */
width: 150%;
top: -25%; /* 50/2 to make sure its center is same as the parent's */
left: -25%; /* 50/2 to make sure its center is same as the parent's */
background: black;
z-index: -2; /* send it behind both the parent and other pseudo */
}
/* add animation when hovering on parent */
.shape:hover:before {
animation: rotate 3s linear infinite;
}
.shape:hover:after {
animation: rotate-rev 3s linear infinite;
}
#keyframes rotate {
to {
transform: rotate(359deg); /* some browsers don't display spin when it is 360 deg */
}
}
#keyframes rotate-rev {
to {
transform: rotate(-359deg); /* reverse direction rotate */
}
}
<div class='shape'></div>
Here's one with the original structure and just one keyframe statement:
All that needs changing, per div, is the animation duration and direction. The "middle" div's timing needs to be 50% of the outer/inner.
.mainSquare {
width: 160px;
height: 160px;
background: black;
margin: 50px auto;
padding: 25px;
animation: spin 2s infinite linear;
}
.firstInnerSquare {
width: 110px;
height: 110px;
background: red;
padding: 25px;
animation: spin 1s infinite linear reverse;
}
.lastInnerSquare {
text-align: center;
width: 110px;
padding: 46px 0px;
background: white;
animation: spin 2s infinite linear;
}
#keyframes spin {
to {
transform: rotate(1turn);
}
}
<div class="mainSquare">
<div class="firstInnerSquare">
<div class="lastInnerSquare">
Hello
</div>
</div>
</div>