javascriptjquerycsscss-transitionsjquery-2.0

Changing css with jQuery 2.1+ ignores transition property


I am switching from jQuery 2.0.3 to 2.1.0.

I noticed that in v2.1.0 the css transition property is ignored when setting css properties directly

$('#someElement').css('width','100px');

In v2.0.3 , my element will maintain it's css transition, whereas I lose that in v2.1.0.

I am wondering why this is treated differently, and how I can 'turn on' the transition effect.

With jQuery 2.0.3, the css transition property takes effect

$(function() {
  $('.myClass').css('width', '100px');
});
.myClass {
  height: 50px;
  width: 300px;
  background-color: red;
  transition: width 3s;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<div class="myClass"></div>

With jQuery 2.1.0, the css transition property is ignored

$(function() {
  $('.myClass').css('width', '100px');
});
.myClass {
  height: 50px;
  width: 300px;
  background-color: red;
  transition: width 3s;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="myClass"></div>

Edit:

I am seeing this odd behavior in Chrome Version 47.0.2526.106 m

In Firefox 42.0, both animate properly


Solution

  • After searching around, I think this may be related to the changes made for issue #14164 during the v2.1.0 release. As per the title, "Reduce forced layout reflows in init or methods".

    I compared the v2.0.3 source code with the v2.1.0 source code, and it looks like some refactoring was done around the .ready() method and how the events are deferred. More specifically, I think it may be related to line(s) 3407-3408 in v2.1.0 where the .ready() method is initially invoked (this wasn't present in v2.0.3):

    // Kick off the DOM ready check even if the user does not
    jQuery.ready.promise();
    

    As for a workaround, it seems like this transition behavior is inconsistent across browsers. To resolve the issue in Chrome, you could defer the execution of the code and force a redraw.

    setTimeout(function () {
      $('.myClass').css('width', '100px');
    }, 0);
    .myClass {
      height: 50px;
      width: 300px;
      background-color: red;
      transition: width 3s;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
    <div class="myClass"></div>


    Alternatively, you could also load jQuery after the DOM elements by moving the script to the bottom of your page. It's still baffling why this makes a difference in Chrome, but doesn't matter in Firefox; it must be related to how the DOM is drawn/painted after events.

    $('.myClass').css('width', '100px');
    .myClass {
      height: 50px;
      width: 300px;
      background-color: red;
      transition: width 3s;
    }
    <div class="myClass"></div>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>