Better way to animate an entering element with `@keyframes`

I was building a demo playing around with an "entering" and "leaving" full page element using both transform and @keyframes, I'm satisfied with the transform result but the @keyframes one involved a lot of js to make the animation "goes backwards" when the user hits the "toggle" button, there is a better approach for it? here's my pen: https://codepen.io/eduruiz/pen/oNaErPr ps. first time posting here, hi everyone! ๐Ÿงก
Edu Ruiz
CodePen
oNaErPr
...
4 Replies
Chris Bolson
Chris Bolsonโ€ข2y ago
As always I have no doubt that there are better ways to do this but you could simplify your JavaScript by creating a variable to save the toggle state and then add or remove classes according to the state.
const content = document.querySelector('.search-keyframes');
let isOpen = false; // toggle state - default closed
function handleClick(){
if (isOpen) {
// already open - close it
content.classList.add('search-keyframes__hide');
content.classList.remove('search-keyframes__open');
isOpen = false;
} else {
// closed - open it
content.classList.add('search-keyframes__open');
content.classList.remove('search-keyframes__hide');
isOpen = true;
}
}
const content = document.querySelector('.search-keyframes');
let isOpen = false; // toggle state - default closed
function handleClick(){
if (isOpen) {
// already open - close it
content.classList.add('search-keyframes__hide');
content.classList.remove('search-keyframes__open');
isOpen = false;
} else {
// closed - open it
content.classList.add('search-keyframes__open');
content.classList.remove('search-keyframes__hide');
isOpen = true;
}
}
(Note - I have moved the const content declaration to be outside of the function as otherwise the code will have to search the DOM to select it every time you click on the button)
Joao
Joaoโ€ข2y ago
On the animationend listener to remove the callback function, you could instead add the listener and pass the option once: true. That would save you a couple of lines of code, though for this purpose the way you are doing it seems about right. It just takes this much boilerplate code. One way you could make it simpler is if you add a couple of classes to your element, making it already on the hidden state but also making it invisible intentionally as otherwise the out animation will play when the page loads:
<div class="search search-keyframes search-keyframes__hide invisible">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Soluta, voluptate.
<input type="search">
</div>
<div class="search search-keyframes search-keyframes__hide invisible">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Soluta, voluptate.
<input type="search">
</div>
.invisible {
visibility: hidden;
}
.invisible {
visibility: hidden;
}
Later in JavaScript you remove this class when you select the element, making it visible again but it will already be hidden because of the other 'end state' you used. From then on it's as simple as toggling the open/hide classes.
const content = document.querySelector('.search-keyframes');
content.classList.remove('invisible');

function handleClick() {
content.classList.toggle('search-keyframes__open');
content.classList.toggle('search-keyframes__hide');
}

document.querySelector('.button__keyframes').addEventListener('click', handleClick);
const content = document.querySelector('.search-keyframes');
content.classList.remove('invisible');

function handleClick() {
content.classList.toggle('search-keyframes__open');
content.classList.toggle('search-keyframes__hide');
}

document.querySelector('.button__keyframes').addEventListener('click', handleClick);
duruiz
duruizOPโ€ข2y ago
I've been out of discord for some days, sorry for the late reply! thanks for the solutions, both are really simpler than what I've been doing. ๐Ÿ™‚ @Chris made it in a way I would think if I was working with vue, a "state like" thinking of the component that I usually don't bring aboard when using pure js. and @joao6246, I totally forgot about the once possibility, that will be very welcome. I had tough about the "one more class" approach but I was like "oh no, one more class to handle"... what I didn't tough is that I could simple just remove it on page load, this make it seems nicer but there isn't the possibility of a "flash of animation" if for exemple my animation took longer to animate than my js took to remove the invisible class?
Joao
Joaoโ€ข2y ago
I guess it really depends on how you like to work and organize yourself. I normally use such utility classes to make things invisible, shrink, grow, etc., so it doesn't feel like "one more class to maintain" to me. It's just a matter of opinion. If you experience any "flashing animations" on page load you can use setTimeout to delay when to remove the visible class. For example if the animation lasts 1 second that could be the same time you use.
Want results from more Discord servers?
Add your server