Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CSS animation won't trigger on addClass in jQuery

I have a very strange issue. I'm loading articles from JSON in jQuery and as they load, I'd like to add a class of 'animate' to each dynamic element.

$.each(jsonArticles, function (i, article) {

    var $articleHTML = $(
    '<article class="article">' +
        '<a href="' + jsonObject.filmLink + article.reviewLink + '"><img src="' + jsonObject.imagePath + article.reviewImage + '" alt=""></a>' +
        '<h1><a href="' + jsonObject.filmLink + article.reviewLink + '">' + article.reviewTitle + '</a></h1>' +
        '<p><a href="' + jsonObject.filmLink + article.reviewLink + '">' + article.reviewSummary + '</a></p>' +
    '</article>');

    $articles
        .append($articleHTML)
            .find("article")
                .addClass("animate");

});

All of this works great and checking in Firebug reveals that the class is successfully added to each article tag.

However, when trying to use a CSS transition on the article for the class that's added, it does not animate, but instead skips straight to the final style (opacity: 1).

.article { 

opacity: 0;

    -webkit-transition: all 0.5s ease;
    -moz-transition: all 0.5s ease;
    -o-transition: all 0.5s ease;
    transition: all 0.5s ease;

}

.article.animate { 

    opacity: 1;

}

The animation doesn't happen, but the class is added and the article is successfully set to opacity: 1. It shows up instantly.

Anyone have any ideas about this? I cannot figure this one out at all.

On another point, which is rather interesting...if I change the .animate class to have a :hover, then the articles won't show until I hover and the animation does work. Why it would work for hover and not when it's simply added immediately, seems strange to me.

.article.animate:hover { 

    opacity: 1;

}

I'd appreciate any input.

Thanks, Mikey.


Live Demo: http://jsfiddle.net/Pz5CD/ Notice how the articles just pop in at 100% opacity. No animation is seen.

like image 907
Michael Giovanni Pumo Avatar asked Jan 05 '14 20:01

Michael Giovanni Pumo


2 Answers

Update:

It turns out the OP wants to fade in each element sequentially, which is beyond the scope of the original question. I'll leave my answer here as an answer to the original question.

CSS animation won't trigger on addClass in jQuery

The issue is that your new html is added to the page and the animate class is added before the css for that html has been applied. The browser will skip ahead like that for the sake of efficiency. For example, if you added a class, then removed it, and repeated that process a hundred times, there wouldn't be a visual difference. It would have just skipped to the result. For this reason, you have to force a redraw on the element so that all previous styles have applied before adding the class. I wrote a function to handle this that should work in every circumstance on every browser, though there's no way to guarantee the behavior of a reDraw. It probably will always work and it's nice to have!

Live demo here (click). You can tell the reDraw is making the difference by commenting it out and just leaving the addClass().

$('body').append($articleHTML);
$a = $('body').find("article");
reDraw($a).then(function() {
  $a.addClass("animate");
});

function reDraw($element) {
  var deferred = new $.Deferred();
  setTimeout(function() {
    var h = $element[0].offsetHeight;
    var s = $element[0].getComputedStyle;
    deferred.resolve();
  },0);
  return deferred.promise();
}

The best way to force a redraw is to either access the offsetHeight or getComputedStyle of an element. However, there have been cases where those have failed for force a redraw on certain mobile devices. To add some extra encouragement for a redraw, I added a setTimeout as well. Even a time of 0 on the timeout will work, but it throws off the call stack, so I use a promise to ensure the next operation (adding your class) will happen after the redraw. That just means you'll use the syntax I demonstrated above to add the class - redraw($element).then(function() { //your code

For fun, I made a little demo of flipping classes with and without reDraw. http://jsbin.com/EjArIrik/1/edit

like image 170
m59 Avatar answered Nov 20 '22 19:11

m59


You need to add the class to the element after it is rendered to the dom, a set timout might work

setTimeout(function(){
    $articleHTML.addClass("animate");
}, i * 500 );

http://jsfiddle.net/Pz5CD/1/

like image 5
Musa Avatar answered Nov 20 '22 18:11

Musa