Huy's Notes
Setting multiple CSS properties at once with jQuery doesn't batch

Setting multiple CSS properties at once with jQuery doesn't batch


There's a trick that was suggested in a few articles on the internet, that whenever you should modify a lot of CSS properties, you should batch them in one call:

  // instead of this
  $('body').css('backgound-color', '#F00');
  $('body').css('width', 100);
  $('body').css('height', 300);

  // do this
    'background-color': '#F00',
    'width': 100,
    'height': 300

By groupping them in one place, we hope that jQuery is smart enough to batch everything into one call.

Turned out, it's not.

If you look at jQuery source code, where the call to jQuery.css starts:

File: jquery/src/css.js#L396

  css: function( name, value ) {
    return access( this, function( elem, name, value ) {

It will then called the access function to determine if the passed parameter is a single style change or a bulk changes:

File: jquery/src/core/access.js#L10

  var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
    // Sets many values
    if ( toType( key ) === "object" ) {
      chainable = true;
      for ( i in key ) {                                        // <===
        access( elems, fn, i, key[ i ], true, emptyGet, raw );  // <===

As you can see here, jQuery didn't attempt to batch anything when it received a key-valued object passed into .css() method, and eventually, it changes the CSS properties directly via<property> = value:

File: jquery/src/css.js#L256

  if ( isCustomProp ) {
    style.setProperty( name, value );
  } else {
    style[ name ] = value;

So, what's the point of batching the CSS properties into one .css() call here?

It's the selector, since our initial example is too simple, let me show you another one:

  $('.container h3[data-tag="product-header"]:not(.hidden) a[href]').css('background', '#F00');
  $('.container h3[data-tag="product-header"]:not(.hidden) a[href]').css('width', 500);
  $('.container h3[data-tag="product-header"]:not(.hidden) a[href]').css('height', 30);

Do you see the problem now? Yes, that monsterous query selector! Querying a DOM element is costly, so don't do it repeatly, batching them all in to one call will save you the cost of querying.

  $('.container h3[data-tag="product-header"]:not(.hidden) a[href]').css({
    'background-color': '#F00',
    'width': 500,
    'height': 30

At least, we solved some performance issue, althought it's not the one we intended to solve, but better than nothing.

Hail jQuery!

Referred in

If you think this note resonated, be it positive or negative, please feel free to send me an email and we can talk.