Skip to content
Advertisement

Unable to make CSS animation centered

I’m working on this CSS animation from Animista which is not centered. The entry animation starts and ends not centered and the exit animation starts in the middle and slides down. Which is not how the animation is supposed to work.

The animation is for a popup which gets triggered after a 1-2 seconds and when the user clicks the close button the popup should disappear.

Here’s the snipper:

const allEl = document.querySelectorAll('body > *:not(#popup):not(script)');
const closeBtn = document.querySelector('#popup-close-btn');
const popup = document.querySelector('#popup');

allEl.forEach(el => {
  el.setAttribute('id', 'blur');
});

const blur = document.querySelector('#blur');

setTimeout(() => {
  blur.classList.add('active');
  popup.style.display = "block";
  popup.classList.add('slide-in-fwd-center');
  popup.classList.remove('slide-out-fwd-center');
}, 2000);

closeBtn.addEventListener('click', () => {
  blur.classList.toggle('active');
  popup.classList.add('slide-out-fwd-center');
  popup.classList.remove('slide-in-fwd-center');
});
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  position: relative;
}

#blur.active {
  filter: blur(10px);
  pointer-events: none;
  user-select: none;
}

a {
  position: relative;
  padding: 5px 20px;
  display: inline-block;
  margin-top: 20px;
  text-decoration: none;
  color: #fff;
  background: #111;
}

#popup {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate( -50%, -50%);
  padding: 50px;
  box-shadow: 0 5px 30px rgba(0, 0, 0, .30);
  width: 600px;
  background: #fff;
  display: none;
}

.slide-in-fwd-center {
  animation: slide-in-fwd-center 0.4s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
}

@keyframes slide-in-fwd-center {
  0% {
    transform: translateZ(-1400px);
    opacity: 0;
  }
  100% {
    transform: translateZ(0);
    opacity: 1;
  }
}

.slide-out-fwd-center {
  animation: slide-out-fwd-center 0.7s cubic-bezier(0.550, 0.085, 0.680, 0.530) both;
}

@keyframes slide-out-fwd-center {
  0% {
    -webkit-transform: translateZ(1);
    transform: translateZ(1);
    opacity: 1;
  }
  100% {
    -webkit-transform: translateZ(600px);
    transform: translateZ(600px);
    opacity: 0;
  }
}
<div class="container">
  <div class="content">
    <h2>
      Lorem ipsum dolor sit amet consectetur adipisicing elit. Cum, harum aspernatur. Hic corrupti inventore voluptatum suscipit soluta sapiente odit delectus, beatae dolor, ea minus nesciunt distinctio dolore nihil itaque odio.
    </h2>
  </div>
</div>

<div id="popup">
  <h2>Lorem safasfasflijlkasfj oafljka aufhskafkl asoifj </h2>
  <p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Velit dolore, recusandae enim quisquam nisi, architecto hic sed fugit modi quibusdam odit quia illum ipsa doloremque at reiciendis vitae nam inventore.</p>
  <a href="#" id="popup-close-btn">Close</a>
</div>

What am I doing wrong here?

Advertisement

Answer

Here is another approach to add to answers presented:

The #popup element is position:absolute, hence to have it centered you could take advantage of calc() in CSS, as this function allows for mixing of units (like calc(50% - 300px)), being the 300px half of your popup’s width (600px):

left: calc(50% - 300px);

However, then I noticed that for some reason the translateZ() would not work as expected.

Initial thought:
Should we use translateZ() in your case?
Bescause the CSS function translateZ() repositions an element along the z-axis in 3D space, hence it is more appropiate for 3D objects.
MDN translateZ()

However, here we have a plain 2D popup. Hence, we could use 2D CSS transform functions instead.

Following now 2 alternatives for 2D transformations:

  1. slide-in / slide-out
    translate(x, y)
  2. zoom-in / zoom-out
    scale(x)

2D slide-in / slide-out

Without zoom effect to begin with, replacing translateZ() with translate(x, y):

const allEl = document.querySelectorAll('body > *:not(#popup):not(script)');
const closeBtn = document.querySelector('#popup-close-btn');
const popup = document.querySelector('#popup');

allEl.forEach(el => {
  el.setAttribute('id', 'blur');
});

const blur = document.querySelector('#blur');

setTimeout(() => {
  blur.classList.add('active');
  popup.style.display = "block";
  popup.classList.add('slide-in-fwd-center');
  popup.classList.remove('slide-out-fwd-center');
}, 2000);

closeBtn.addEventListener('click', () => {
  blur.classList.toggle('active');
  popup.classList.add('slide-out-fwd-center');
  popup.classList.remove('slide-in-fwd-center');
});
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  position: relative;
}

#blur.active {
  filter: blur(10px);
  pointer-events: none;
  user-select: none;
}

a {
  position: relative;
  padding: 5px 20px;
  display: inline-block;
  margin-top: 20px;
  text-decoration: none;
  color: #fff;
  background: #111;
}

#popup {
  position: absolute;
  top: 50%;
  left: calc(50% - 300px);
  padding: 50px;
  box-shadow: 0 5px 30px rgba(0, 0, 0, .30);
  width: 600px;
  background: #fff;
  display: none;
}

.slide-in-fwd-center {
  animation: slide-in-fwd-center 0.4s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
}

@keyframes slide-in-fwd-center {
  0% {
    transform: translate(-1400px, -1400px);
    opacity: 0;
  }
  100% {
    transform: translate(0, 0);
    opacity: 1;
  }
}

.slide-out-fwd-center {
  animation: slide-out-fwd-center 0.7s cubic-bezier(0.550, 0.085, 0.680, 0.530) both;
}

@keyframes slide-out-fwd-center {
  0% {
    -webkit-transform: translate(0, 0);
    transform: translate(0, 0);
    opacity: 1;
  }
  100% {
    -webkit-transform: translate(1400px, 1400px);
    transform: translate(1400px, 1400px);
    opacity: 0;
  }
}
<div class="container">
  <div class="content">
    <h2>
      Lorem ipsum dolor sit amet consectetur adipisicing elit. Cum, harum aspernatur. Hic corrupti inventore voluptatum suscipit soluta sapiente odit delectus, beatae dolor, ea minus nesciunt distinctio dolore nihil itaque odio.
    </h2>
  </div>
</div>

<div id="popup">
  <h2>Lorem safasfasflijlkasfj oafljka aufhskafkl asoifj </h2>
  <p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Velit dolore, recusandae enim quisquam nisi, architecto hic sed fugit modi quibusdam odit quia illum ipsa doloremque at reiciendis vitae nam inventore.</p>
  <a href="#" id="popup-close-btn">Close</a>
</div>

2D zoom-in / zoom-out

Using scale(x):
Note:

  • 0% to 99%: We animate the zoom (scale()), and then …
  • 99% to 100%: move the popup out of screen (translate())
    (otherwise the content underneath would be covered by our invisible opacity:0 popup)

const allEl = document.querySelectorAll('body > *:not(#popup):not(script)');
const closeBtn = document.querySelector('#popup-close-btn');
const popup = document.querySelector('#popup');

allEl.forEach(el => {
  el.setAttribute('id', 'blur');
});

const blur = document.querySelector('#blur');

setTimeout(() => {
  blur.classList.add('active');
  popup.style.display = "block";
  popup.classList.add('slide-in-fwd-center');
  popup.classList.remove('slide-out-fwd-center');
}, 2000);

closeBtn.addEventListener('click', () => {
  blur.classList.toggle('active');
  popup.classList.add('slide-out-fwd-center');
  popup.classList.remove('slide-in-fwd-center');
});
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  position: relative;
}

#blur.active {
  filter: blur(10px);
  pointer-events: none;
  user-select: none;
}

a {
  position: relative;
  padding: 5px 20px;
  display: inline-block;
  margin-top: 20px;
  text-decoration: none;
  color: #fff;
  background: #111;
}

#popup {
  position: absolute;
  top: 50%;
  left: calc(50% - 300px);
  padding: 50px;
  box-shadow: 0 5px 30px rgba(0, 0, 0, .30);
  width: 600px;
  background: #fff;
  display: none;
}

.slide-in-fwd-center {
  animation: slide-in-fwd-center 0.4s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
}

@keyframes slide-in-fwd-center {
  0% {
    -webkit-transform: scale(5);
    transform: scale(5);
    opacity: 0;
  }
  100% {
    -webkit-transform: scale(1);
    transform: scale(1);
    opacity: 1;
  }
}

.slide-out-fwd-center {
  animation: slide-out-fwd-center 0.7s cubic-bezier(0.550, 0.085, 0.680, 0.530) both;
}

@keyframes slide-out-fwd-center {
  0% {
    -webkit-transform: scale(1);
    transform: scale(1);
    opacity: 1;
  }
  99% {
    -webkit-transform: scale(5);
    transform: scale(5);
    opacity: 0;
  }
  100% {
    -webkit-transform: scale(5);
    transform: scale(5);
    -webkit-transform: translate(1400px, 1400px);
    transform: translate(1400px, 1400px);
    opacity: 0;
  }
}
<div class="container">
  <div class="content">
    <h2>
      Lorem ipsum dolor sit amet consectetur adipisicing elit. Cum, harum aspernatur. Hic corrupti inventore voluptatum suscipit soluta sapiente odit delectus, beatae dolor, ea minus nesciunt distinctio dolore nihil itaque odio.
    </h2>
  </div>
</div>

<div id="popup">
  <h2>Lorem safasfasflijlkasfj oafljka aufhskafkl asoifj </h2>
  <p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Velit dolore, recusandae enim quisquam nisi, architecto hic sed fugit modi quibusdam odit quia illum ipsa doloremque at reiciendis vitae nam inventore.</p>
  <a href="#" id="popup-close-btn">Close</a>
</div>

Final comment:
You are assigning an id attribute (#blur) to acces all direct children elements of the <body> for the blur-effect. It is OK in your code snippet that you have presented, because your body has only 1 direct child (parent-child selector > , hence <div class="container" id="blur">).

But what if we had several direct children elements, like header, content and footer?
Then, our id #blur would not be unique anymore within our DOM, as it would repeat multiple times.

You might consider modifying your code by replacing the id #blur with a class .blur, hence:

CSS:

.blur.active {
  filter: blur(10px);
  pointer-events: none;
  user-select: none;
}

JS:

allEl.forEach(el => {
  el.classList.add('blur');
});
User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement