CSS Triggers

I figure we needed a definitive reference for what work is triggered by changing various CSS properties. It's something I get asked about often enough by developers, and while we can do tests with DevTools, I have both the time and inclination to shortcut that for everyone. I'm nice like that.

  • Last updated: 26 Jul 2014
  • Est. Read Time: 5 mins
  • Tagged: #perfmatters, #reference

Visit CSS Triggers

A while ago, Paul Irish and I were doing an event in San Francisco about performance. In Paul’s deck there was a grab of a doc we’d collaborated on that showed the top CSS properties by usage, along with their impact to browser workload. The ‘impact’ part was incomplete, and manually created, but I guess in many ways that was the starting point for making CSS Triggers. Except this time I wanted it to be complete and automated…

Building the data set

The first thing I knew I would want was a set of test pages that would allow me to check each CSS property individually and see what it triggered. But wait, I’m getting ahead of myself, how do I get all the CSS properties? After a bit of googling I found someone had tried something similar. Their code was a bit much for my needs so I rewrote it and simplified things, and it turned out the final code to get the properties was actually not too tricky at all:

var docEl = document.documentElement;
var properties = window.getComputedStyle(docEl, null);
var prefix = /\-webkit\-/;
var allCSSProperties = [];

for (var s = 0; s < properties.length; s++) {
  var property = properties[s];

  // Ignore prefixed properties.
  if (prefix.test(property))
    continue;

  // Check we don't duplicate.
  if (allCSSProperties.indexOf(property) == -1)
    allCSSProperties.push(property);
}

And now I had a list of properties…

Test files

Next I created a node.js file that would output a suite of test files, one for each property. Each file in the suite is pretty much the same, save for the property it manipulates. And. They. Look. Gorgeous.

My gorgeous test files. DON'T JUDGE ME.

For each property I made sure that will-change was set (even if there’s no corresponding browser optimization to match, because whatevs) and that the value changes actually did trigger something.

For each property I made sure that will-change was set (even if there’s no corresponding browser optimization to match, because whatevs) and that the value changes actually did trigger something. By that I mean there’s no point changing a property intended for tables if you have no tables, that kind of thing. I also tried to make sure there was a test of changing the value from its default to something else, and then another test changing it between two user-defined values, if that made sense for the property in question.

You have tests, you run them…

OK, suite of tests all ready and working, I set about cloning Chrome’s Telemetry and making a benchmark to run through all the files. Sounds simple, but Telemetry is a large codebase and I don’t pretend to understand Python super well. Anyways, I got there.

The key with Telemetry, though, is that you can ask it to record a DevTools timeline of the page and then see which records it received. The way I built the test was that the CSS property change would be triggered by a specific go() function (rad naming, I know) so for each page in the set I essentially said:

  • Load it.
  • Switch on DevTools’ Timeline.
  • go()
  • Stop DevTools’ Timeline.
  • Tell me if you have Layout, Paint or Composite Records.

With that, and a bit more data jiggery pokery, I ended up with a big ol’ data set.

Go static or … go home?

Building the site was a relatively clear once I had the data: a big table with some details on what it means. But to generate it I wanted to use Jekyll, so I found myself writing more node.js stuff to transform the JSON I had over to its funky YAML front matter:

properties:
 - name: "align-content"
   chrome:
      initial:
         layout: "true"
         paint: "true"
         composite: "true"
      change:
         layout: "null"
         paint: "null"
         composite: "null"
 - name: "align-items"
   chrome:
      initial:
         layout: "true"
         paint: "true"
         composite: "true"
      change:
         layout: "null"
         paint: "null"
         composite: "null"

  # etc, etc....

You may well notice a “chrome” key there in the data. That’s right. I’d like to expand this to other browser vendors, and I am more than happy to include more data and give developers a better overview. Sadly the tools don’t exist yet for many browsers, so here’s a request: if you’re a vendor, or you know what’s going on inside browsers besides Chrome, please file a Pull Request. As I get data I will update the site.

I’d like to expand this to other browser vendors, and I am more than happy to include more data and give developers a better overview.

Have data, will travel

I wanted to create a tool that would allow developers to more readily understand the ramifications of changing their styles. I’m pleased with the first release of CSS Triggers, and I hope many folks get good use out of it. I have plans to expand the site a bit more so that the reference has context, not just a load of data, but I’m not sure exactly when that will be.

Putting together the site was fun, and involved a heck of a lot of tool and data wrangling, but in the end I like to think it was worth it. But then I would say that…