No, CSS isn’t always faster

Recently, a post appeared on Hacker News that was yet another exploration of crazy things that can be achieved with CSS.  Like many others, this example was logos rendered using HTML & CSS.  I quickly commented that I didn’t feel we needed more of these examples which, while cool, do almost nothing to advance web development in general. (Note: as Nicolas Gallagher, mentioned in the comments, his article clearly states that these his icons are an experimentation and shouldn’t be deployed in a real-world environment; apologies if the initial text implied that these demonstrations are endorsements of the “use this in the wild” approach).  I suggested that the people involved in such endeavors would be better suited devoting their efforts to demonstrating tips and techniques applicable to the real world.

While I’m sure I could devote an entire post to why CSS is the wrong tool for this job (see the “related reading” section below for a great argument there), one response to my comment in particular caught my attention:

A CSS logo would be useful for performance issues and overall page rendering speed. A CSS animated logo, such as the Atari example, even moreso than a Flash / JS counterpart. CSS renders more quickly than images, and definitely more quickly than embedded Flash.

It’s time for this misinformed, dogmatic approach to web performance to end.  

When Steve Souders came out with his book, High Performance Websites, and the accompanying YSlow tool, the race to reduce HTTP requests was on! Several years later, it’s somewhat unfortunate that in all of the great advice that Steve doled out, many people never make it past this first bullet point. It’s also unfortunate that this rule set has defined website performance for the masses primarily in terms of network-related bottlenecks.  It’s some to start thinking about performance from a holistic point of view; and not isolating things like network performance and elevating them to higher importance than other concerns.

Note: I mention Steve Souders’ work here here not to blame him for what’s happened; more to make the point that good practices (like those Steve suggests) put to use by people without understanding the full ramifications of that advice can lead to some nasty misconceptions.

Thinking about performance holistically, I’m immediately reminded of the talks John Resig did shortly after Sizzle was released and competitors started popping up everywhere to convince people that selector engines were no longer the performance bottleneck in Javascript. People had become obsessed with a single point of performance and were ignoring the “bigger fish.”

So here we are in 2011, and people are still regurgitating the idea that “using CSS is faster than images” without truly understanding the implications of that statement (and how untrue it can be under the right circumstances).  An analogy that I like to use comes from the world of 3D gaming: Rendering something (for example, a drop shadow) in CSS and markup is the real-time, in-game rendering while downloading an appropriately compressed drop shadow png image is using a pre-rendered full-motion-video cut scene. Sure, the initial payload may be somewhat heavier; but again, looking at the complete picture, pre-rendering allows for overall higher performance.

I mention the drop shadow example because it’s absolutely real.  When the team at Netflix was building the initial versions of our web-based UI for connected devices, we ran into serious performance problems on all sorts of devices like the PlayStation3. One of the things we found that significantly sped up the application was to avoid using CSS effects like shadows, gradients, and other “CSS effects;” instead, favoring pre-rendered effects. In some cases, the performance gains were nothing short of astonishing.

To the examples provided by the initial Hacker News article, let’s look at the Twitter logo demonstration. It’s 27 DOM elements and over 4 kilobytes of CSS.  So already we have a comparably sized payload, a more complex DOM, and now it’s time to add flow and paint operations to actually do the rendering of the elements.  There’s a lot of calculations happening to position and style the elements to appear as the Twitter logo.  By using an image, we bypass the calculations on layout and painting that need to be done to do the rendering; those calculations were already completed.

Performance is more than optimizing for the network layer and initial load-time of a page. As with anything, there are tradeoffs to be made (add a little download time, speed up the rendering) and in different situations, there will be different speed winners based on those tradeoffs. More interesting when working with lower-end devices (such as mobile devices) are the tradeoffs between memory use and computation cycles that I hope to cover in depth in future blog posts.

Sadly, there are few resources that cover the topic of in-browser performance in any more depth than a cursory level. I’ve only touched on it here; though I do hope to continue writing about it. That said, before we can even start talking intelligently about working on performance from a holistic approach rather than focusing on individual concerns, we need to learn to get past the dogmatic rules that are holding us back.

Related Reading: Pure CSS Icons: Make the Madness Stop

  • http://twitter.com/necolas Nicolas Gallagher

    Hey, since you linked to one of my blog posts and supplied a suggestion…

    My post clearly states that it is experimentation. And in another post about GUI icons, nearly 1 year ago, I wrote this in the comments: “…it isn’t something that I want encourage to be deployed on websites. I don’t think this is practical and I hope people are aware of the limitations. Images and SVG are better tools for the job.” I also replied to the same HN comment as yourself, saying: “CSS is the wrong tool for the job.”

    All my experiments used pseudo-elements and I described a few things that came about from that experimentation. So, while I can’t speak for the experiments of others, I do question your assumption that nothing useful was gained. Pseudo-elements weren’t really being explored at that time. I find time to do a few other things too. Thanks.

  • http://briancrescimanno.com/ Brian Crescimanno

    Hi Nicolas,

    I hope this post didn’t come off as an attack on you (or any of the authors of these examples).  As I said in my original HN comment, these demonstrations take a lot of work and provide some pretty impressive examples of what can be done with markup and CSS.  For what it’s worth, the link to your post came from a quick Google search for other examples of sites where people have built up icons or graphics using CSS.  

    As I hope I communicated, my main concern is with people who look at examples like yours (and the original from HN that spawned my commentary) and take it as a best practice.  I will modify my blog post to comment that, at least in the case of your post, you acknowledge up front that CSS really isn’t the right tool for the job.

    I don’t know that I suggested that nothing useful was gained; but certainly nothing immediately practical. There are many other ways to demonstrate the power of pseudo-elements, for example, in far more realistic scenarios than their use in creating iconography rendered in real-time.

  • http://www.xhtml-css.net/css/xhtml-css-templates-no-css-isnt-always-faster-brian-crescimanno xhtml css templates – No, CSS isn't always faster | Brian Crescimanno | XHTML CSS – Style sheet and html programming tutorial and guides

    [...] here to read the rest: No, CSS isn't always faster | Brian Crescimanno Share and [...]

  • http://twitter.com/necolas Nicolas Gallagher

    “There are many other ways to demonstrate the power of pseudo-elements, for example, in far more realistic scenarios than their use in creating iconography rendered in real-time.”

    Yes. But it came from the shape experiments I did, which is why that experimentation was useful.

  • http://paulirish.com Paul Irish

    I was SOOOOO with you up until you started talking data. But since you brought it up…. :)

    I grabbed an SVG of the twitter bird, and the official png. I then minified the html/css version, and minified the svg. Checked the sizes. Then I gzipped both.. and compared those sizes to a pngquant’d png. You’ll see the results below:

    5470 csstwitter.html
    3068 svgtwitter.svg

    1268 csstwitter.html.gz
    1510 svgtwitter.svg.gz
    2933 pngtwitter.png

    Files available here: http://paulirish.com/lovesyou/csstwitter/

    Now you do mention there may be computational overhead in declarative imagery, which may be true… But I guess I would just say that dogma is always dogma unless there is data. :)

  • http://briancrescimanno.com/ Brian Crescimanno

    I’m not sure I understand your objection here; my mentioning of the file sizes involved with the html / css version of the Twitter bird was to point out that in this “extreme” case, even the perceived advantage of being smaller to download might be a moot point.   In that particular case, prior to magnification (which relatively few people do on CSS; fewer still on markup these days) the payload was actually comparable.  The expectation I was trying to set in the article was that yes, indeed, downloading a pre-rendered image would require more bytes over the wire–but that the overall time to render would likely be quicker due to lack of computational complexity associated with applying the various style rules (especially on low-end devices).

    The SVG example is interesting; though I think it falls squarely into the “CSS probably isn’t the right tool for the job” just based on the language semantics rather than performance characteristics (which would obviously vary based on SVG implementation on a particular platform).

    In my mind, the more interesting data point would be to compare the processing time of the CSS associated with the Twitter bird image vs. the bit blit operation to paint the png to the screen. Sadly, I don’t know of a good way to get at that hard data on desktop-class browsers. I can say with certainty that on some of the devices I work with on a daily basis, the difference is perceptable without any specialized benchmarking tools.