Animating two circles to meet exactly in the middle

784 Views Asked by At

So I'm aiming to have two circles meet from either side of the screen and meet in the middle to perform the second half of the animation (scaling and opacity change).

But by setting the initial keyframe and last using vw they don't meet in the middle - since the vw value is relative to the left side of the div and not the centre (I have used vw as I need this to be responsive). So, what happens is that the left sides of the circle meet in the centre.

Does anyone know a simple fix to this using just css? I am newish to coding, so if the answer is obvious I apologise.

Here is my code:

@keyframes left {
  0% {
    transform: translate3d(0vw, 50%, 0) scale3d(1, 1, 1);
    opacity: 50%;
    animation-timing-function: ease-in;
  }
  60% {
    transform: translate3d(50vw, 50%, 0) scale3d(1, 1, 1);
    opacity: 50%;
    animation-timing-function: ease-out;
  }
  100% {
    transform: translate3d(50vw, 50%, 0) scale3d(2, 2, 1);
    opacity: 0%;
    animation-timing-function: ease-out;
  }
}

@keyframes right {
  0% {
    transform: translate3d(100vw, 50%, 0) scale3d(1, 1, 1);
    opacity: 50%;
    animation-timing-function: ease-in;
  }
  60% {
    transform: translate3d(50vw, 50%, 0) scale3d(1, 1, 1);
    opacity: 50%;
    animation-timing-function: ease-out;
  }
  100% {
    transform: translate3d(50vw, 50%, 0) scale3d(2, 2, 1);
    opacity: 0%;
    animation-timing-function: ease-out;
  }
}

.circleleft {
  overflow: hidden;
  position: absolute;
  background: white;
  border-radius: 50%;
  width: 500px;
  height: 500px;
  animation: left 2s;
  animation-fill-mode: forwards;
}

.circleright {
  overflow: hidden;
  position: absolute;
  background: white;
  border-radius: 50%;
  width: 500px;
  height: 500px;
  animation: right 2s;
  animation-fill-mode: forwards;
}
<div style="width:100vw; height:100vh; background-color:#87827E">
  <div class="circleleft"></div>
  <div class="circleright"></div>
</div>

You can see it in use here too: https://ruairimadine.co.uk/sudoroux

2

There are 2 best solutions below

0
On

One trick is to initially position both circles in the center and the animation/translation will offset them from the left or right.

I optimized the code to only use pseudo-elements and make it easier to understand:

body {
  margin: 0;
  height: 100vh;
  background-color: #87827E;  
  overflow: hidden;
  position:relative;
}
body::before,
body::after{
  content:"";
  position: absolute;
  top: calc(50% - 25vmin);
  left:calc(50% - 25vmin);
  background: white;
  opacity: 50%;
  border-radius: 50%;
  width: 50vmin;
  height: 50vmin;
  animation: move 2s forwards;
}
/* 50vw : half the screen width | 25vmin half the circle width*/
body::before { transform:translateX(calc( 50vw + 25vmin)); }
body::after  { transform:translateX(calc(-50vw - 25vmin)); }

@keyframes move {
  60% {
    transform: translateX(0) scale(1);
    opacity: 50%;
  }
  100% {
    transform: translateX(0) scale(2);
    opacity: 0%;
  }
}

1
On

In this example the circles size is stored in the root variable --circle-size: 100px;. So the circles can be centered with top and left easily. The animation uses the properties left (position), opacity and transform: scale (scaling).

setTimeout(()=>{
  document.querySelector('.circle-left').classList.add('circle__animated');
  document.querySelector('.circle-right').classList.add('circle__animated');
}, 1000);
:root{
    --circle-size: 100px;
}

.circle{
   position: absolute;
   width: var(--circle-size);
   height: var(--circle-size);
   border-radius: 50%;
   top: calc(50% - var(--circle-size)/2);
}

.circle.circle-left{
    background: red;
    left: 0;
    animation: left 2s;
    animation-fill-mode: forwards;
}

.circle.circle-right{
    background: green;
    left: calc(100% - var(--circle-size));
    animation: right 2s;
    animation-fill-mode: forwards;
}



@keyframes left {
  0% {
    left: 0;
    opacity: 1;
    transform: scale(1);
    animation-timing-function: ease-in;
  }
  60% {
    left: calc(50% - var(--circle-size)/2);
    opacity: 0.5;
    transform: scale(1);
    animation-timing-function: ease-out;
  }
  100% {
    left: calc(50% - var(--circle-size)/2);
    opacity: 0;
    transform: scale(5);
    animation-timing-function: ease-out;
  }
}

@keyframes right {
  0% {
    left: calc(100% - var(--circle-size));
    opacity: 1;
    transform: scale(1);
    animation-timing-function: ease-in;
  }
  60% {
    left: calc(50% - var(--circle-size)/2);
    opacity: 0.5;
    transform: scale(1);
    animation-timing-function: ease-out;
  }
  100% {
    left: calc(50% - var(--circle-size)/2);
    opacity: 0;
    transform: scale(5);
    animation-timing-function: ease-out;
  }
}
<div style="position: absolute; top:0; left: 0; width:100vw; height:100vh; background-color:#87827E; padding: 0; margin: 0; overflow: hidden;">
    <div class="circle circle-left"></div>
    <div class="circle circle-right"></div>
</div>