Recently our team is making a big push for general UI performance improvements. Our UI layer is mostly a HTML5 web app that sits on top of ASP.net MVC host. The javascript code base is rather old and poorly factored, so most of our initial efforts were focused onto profiling and cleaning the javascript. We had some success, but our UI is still sluggish in some areas. Soon we began investigating other browser activities like DOM queries and layouts. Using the Chrome developer tool’s awesome “timeline” feature, we discovered that on the sluggish pages, “recalculating styles” is taking up to 2-3 seconds to complete!

This obviously got our attention, so we ran the CSS selector profiler (again, Chrome comes with it preloaded in the developer tools). It turns out that there are some regular expression based selectors that are taking 95% of the calculation time. For example:

[data-sprite$="0"]:before { ... }

[data-sprite$="13"]:before { ... }

[class*="o-content"].role-link { ... }

These selectors walk every single element in the DOM tree and do regular expression matching on its attributes. These searches cannot be indexed and therefore can be extremely slow. Because browsers need to restyle on certain events, it made our UI felt as if the javascript handlers are taking forever to run, while in fact the handlers weren’t even called yet – the browser is busy restyling and not firing the events!

In our case the fix was simple: these selectors were part of an obsolete feature and were returning no matches. Simply deleting these CSS selectors boosts our UI responsiveness nearly 10 times in certain cases. Essentially we were paying a huge cost for a bunch of dead CSS selectors that nobody was using at all.

At the end of the day, a lesson learnt for all of us. So next time when you profile your Web App, make sure you look at the entire picture before jumping into javascript profiling, and also don’t forget: dead CSS is truly deadly!