Fade element out using vanilla javascript and css

Seems like jQuery is way easier to do simple tasks like this but I want to do it with pure javascript instead which seems significantly harder. Anyway, I just want to fade out an element when a button is clicked. I want to use css for the fade but I believe that you cannot transition display: none;

I have tried to first fade out and then totally remove the element but the display:none seems to fire instantly as I don't see the fade out at all.

The css:

.fade-out {
    opacity: 0;
    visibility: hidden;
    transition-property: opacity, visibility;
    transition-duration: 1s, 0s;
    transition-delay: 0s, 1s;
}
.remove-vis {
    display: none;
}

Open in new window


My .then() block:

        .then(response => {
            const pendingLi = deleteBtn.closest('li');
            pendingLi.classList.add('fade-out');
            pendingLi.classList.add('remove-vis');
            btnSet.forEach(query => {
                query.style.visibility = 'visible';
            });
        })

Open in new window

LVL 1
Black SulfurAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Zakaria AcharkiAnalyst DeveloperCommented:
Here is a sample of pure JS fadeIn/fadeOut with the use of CSS "transition" property.

JAVASCRIPT
function fadeIn(el){
  el.classList.add('show');
  el.classList.remove('hide');  
}

function fadeOut(el){
  el.classList.add('hide');
  el.classList.remove('show');
}

document.body.addEventListener('click', e => {
  const deleteBtn = e.target;
  
  if (deleteBtn.classList.contains("delete")) {
    e.preventDefault();

    fadeOut(deleteBtn.parentNode);
  }
});

Open in new window


CSS
.show {
  opacity: 1;
  transition: opacity 1000ms;
}

.hide {
  opacity: 0;
  transition: opacity 1000ms;
}

Open in new window


Here is a sample :

https://jsfiddle.net/z_acharki/rm0xg7dv/2/

The for the delete we could use the setTimeout() since we know the transition delay, so for the provided example, we could use 1000.
Black SulfurAuthor Commented:
I am trying to remove the entire <li>, not just the buttons this time :) And the problem is that with your code there is the nice fade out but there is a huge gap left where the list item was. So, that needs to be removed which I would have done with display:none but of course then you don't get the nice fade effect. I tried adding a height of 0 which sort of works but then I am left with an empty <li> with a class of fade-out which actually still takes up a bit of space.
Zakaria AcharkiAnalyst DeveloperCommented:
So I think it will be better to remove it at all from the DOM after the fadeout like :

function fadeOut(el, callback){
  el.classList.add('hide');
  el.classList.remove('show');
  
  if( callback ){
    setTimeout(function(){
      el.remove();
    }, 1000)
  }
}

document.body.addEventListener('click', e => {
  const deleteBtn = e.target;
  
  if (deleteBtn.classList.contains("delete")) {
    e.preventDefault();

    fadeOut(deleteBtn.closest('li'), 'remove');
  }
});

Open in new window


Sample here :

https://jsfiddle.net/z_acharki/rm0xg7dv/6/

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Determine the Perfect Price for Your IT Services

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden with our free interactive tool and use it to determine the right price for your IT services. Download your free eBook now!

Black SulfurAuthor Commented:
Is it not possible without setTimeout? It will work but not maybe the most elegant solution?
Zakaria AcharkiAnalyst DeveloperCommented:
If you perform any request it will be better to remove it in the success callback, but if you don't you could use setTimeout it will be the correct simple way.
Black SulfurAuthor Commented:
This is a general question. Why is it so easy with jQuery? It is literally just fadeOut() and that solves all problems. It fades the element out and removes it from the DOM completely. And since jQuery is a javascript library, isn't the code behind fadeOut() pure javascript?
Zakaria AcharkiAnalyst DeveloperCommented:
First of all the jQuery fadeOut() just hides the elements and not remove them from the DOM (Official description: Hide the matched elements by fading them to transparent.).

So if we want to remove the element from the DOM we need to specify this in the callback function like :

item.fadeOut('slow', function(){
    item.remove();
})

Open in new window


The callback will be called as we do here after the set of time specified.
Black SulfurAuthor Commented:
Do you know how to do this with 'transition'? I am trying that as well to weigh up my options but it won't fade.

function fadeOut(el) {
	var elem = document.querySelector(el);
	elem.style.transition = "opacity 0.5s linear 0s";
	elem.style.opacity = 0;
}

Open in new window



 .then(response => {
            const pendingLi = deleteBtn.closest('li');
            fadeOut('pendingLi');
            btnSet.forEach(query => {
                query.style.visibility = 'visible';
            });
        })

Open in new window

Zakaria AcharkiAnalyst DeveloperCommented:
Using classes is more efficient than maintaining the inline style, why you can't use classes like the provided example shows?
Black SulfurAuthor Commented:
I have ended up using your method with the classes but I like to learn different things so was just wondering about that. But I prefer the class way, I was just asking, that's all.
Zakaria AcharkiAnalyst DeveloperCommented:
Ok I see, the problem in the previous code was that you're trying to pass a string as a selector so the querySelector can't find it when you have already the DOM object instance (pendingLi) so you just to pass it to the fade function and use it, something like :

function fadeOut(el) {
  el.style.transition = "opacity 0.5s linear 0s";
  el.style.opacity = 0;
}

.then(response => {
  const pendingLi = deleteBtn.closest('li');
  fadeOut(pendingLi);
  btnSet.forEach(query => {
      query.style.visibility = 'visible';
  });
})

Open in new window

Black SulfurAuthor Commented:
Thank you for your patience!
Zakaria AcharkiAnalyst DeveloperCommented:
Welcome anytime, Glad I could help.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
CSS

From novice to tech pro — start learning today.