Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@huytd
Last active September 27, 2019 07:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save huytd/8917b641cd70d5dd611e0cdbc9b0d218 to your computer and use it in GitHub Desktop.
Save huytd/8917b641cd70d5dd611e0cdbc9b0d218 to your computer and use it in GitHub Desktop.

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
  $('body').css({
    '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:

  // https://github.com/jquery/jquery/blob/1b74660f730d34bf728094c33080ff406427f41e/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:

  // https://github.com/jquery/jquery/blob/master/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 change the CSS properties directly via element.style.<property> = value:

  // https://github.com/jquery/jquery/blob/master/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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment