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:
- slide-in / slide-out
translate(x, y)
- 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 invisibleopacity: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'); });