71

Using keyframes, it is possible to animate an element as soon as it is inserted into the DOM. Here's some sample CSS:

@-moz-keyframes fadeIn {
    from {opacity:0;}
    to {opacity:1;}
}

@-webkit-keyframes fadeIn {
    from {opacity:0;}
    to {opacity:1;}
}

@keyframes fadeIn {
    from {opacity:0;}
    to {opacity:1;}
}

#box {
    -webkit-animation: fadeIn 500ms;
    -moz-animation: fadeIn 500ms;
    animation: fadeIn 500ms;
}

Is there some similar functionality available to apply an animation (via CSS, no JavaScript) to an element right before it is removed from the DOM? Below is a jsFiddle I made to play around with this idea; feel free to fork it if you know of a solution.

jsFiddle - http://jsfiddle.net/skoshy/dLdFZ/

Steve
  • 2,023
  • 3
  • 17
  • 25

3 Answers3

23

Create another CSS animation called fadeOut, say. Then when you want to remove the element, change the animation property on the element to that new animation, and use the animationend event to trigger the actual removal of the element once the animation is done:

$('.hide').click(function() {
    if (!$(this).hasClass('disabled')) {
        $('#fill').css('-webkit-animation', 'fadeOut 500ms');
        $('#fill').bind('webkitAnimationEnd',function(){
            $('#fill').remove();
            $('.show, .hide').toggleClass('disabled');
        });
    }
});

See also my updated version of your jsFiddle. That works for me in Safari, at least.

Well, you should be using a class instead of that .css().

I don't think jQuery has any "real" support for CSS animations yet, so I don't think you can get rid of that webkitAnimationEnd. In Firefox it's just called animationend.

I'm pretty sure there's no way to do this in just CSS.

mercator
  • 28,290
  • 8
  • 63
  • 72
  • This is pretty clever, but if I'm going a JavaScript route I could just call `$('#fill').fadeOut()`. What I'm really looking for is a CSS only solution - I didn't know fading in an element was possible until I viewed many forums, so I'm hoping someone knows how to fade out an element too. – Steve Aug 10 '11 at 02:40
  • 8
    But `.fadeOut()` uses JavaScript to do the animation. This actually uses CSS for the animation. It just uses JavaScript to trigger it at the right time. And since you're using JavaScript anyway to actually insert/remove the element, "CSS only" is kind of arbitrary. There's just no way to trigger something in CSS to happen just before it is removed. If you turned those "click me" divs into links, you might be able to use `.hide:active + #fill` as a selector to trigger the fading out, but then you'd still need an `animationend` event to actually remove the element when it's faded out. – mercator Aug 10 '11 at 07:14
  • @S.K.: In short, no. CSS is not related to DOM manipulation like adding and removing elements. The FadeIn trick works because the animation happens whenever the element first appears simply because that's the first moment it CAN happen. In order for an element to know to FadeOut, it would need to know that it's about to be removed, and that is only possible with Javascript. And as mercator said, since you're already using Javascript to remove the element, the "CSS-only" requirement is arbitrary. – joequincy Nov 16 '12 at 19:08
  • @mercator: your jsFiddle version does not work on 2 major browsers where I tested, Firefox and MSIE! It works on other 2 though. – Pointer Null Dec 30 '13 at 11:39
  • @PointerNull, indeed not, since I only added the webkit-prefixed CSS and event handler. This one works for standards-compliant browsers too: http://jsfiddle.net/dLdFZ/63/ – mercator Jan 07 '14 at 09:55
9

I've been working on a component library for javascript and I ran into this problem myself. I have the benefit of being able to throw a ton of javascript at the problem, but since you're already using a bit, consider the following for a gracefully degrading solution:

On removal of any component/dom node, add a class called 'removing'.

Then in the css you can define your animation using that class:

.someElement.removing {
    -webkit-animation: fadeOut 500ms;
    -moz-animation: fadeOut 500ms;
    animation: fadeOut 500ms;
}

And back in the javascript, just after you add the 'removing' class, you should be able to check for the 'animation' css property, and if it exists, then you know that you can hook on 'animationEnd' and if it doesn't, then just remove the element right away. I remember testing this a while back, it should work; I'll see if I can dig up the example code.

Update: I've dug up this technique and started writing a really cool plugin for jQuery that allows you to use CSS3 animations for DOM elements that are being removed. No additional Javascript required: http://www.github.com/arthur5005/jquery.motionnotion

It's very experimental, use at your own risk, but would love some help and feedback. :)

Arthur Goldsmith
  • 2,976
  • 2
  • 17
  • 7
  • Very interesting. When you add support for the other functions like `append()` and `prepend()`, I'll start using it. How does it compare to https://github.com/ai/transition-events ? – Steven Vachon Dec 04 '13 at 00:18
  • 1
    Hey Steve, this is mostly for other people, I've updated the plugin to support append() and prepend(). :) – Arthur Goldsmith Feb 17 '14 at 22:22
-9

ideally for something like fadeIN and fadeOUT you should be using css transitions not css animations..

Naman Goel
  • 1,525
  • 11
  • 16