or: "Reports of the Harm Caused By CSS Variables Are Greatly Exaggerated"
To say that CSS is abominable isn't controversial. The implementations are leading the spec in some places, and we're getting real progress there. Firefox's rounded corners and WebKit's drop-shadows, declarative animations, background tiling, and CSS variables are all hugely important and liberating. But where the spec is in-front of the important implementations...well, I've ranted before on the topic. CSS sucks, and the editor of the spec has now written at length of his intent to keep it that way (via Simon). His arguments are flim-flam, but just saying so isn't enough to convince any one. Making the case requires answering long-hand and showing our work.
By The Numbers
Lets look first at the numbers presented in the sidebar here. Remember that the survey numbers come from documents on the W3C website. The article would have us believe that this sample set bears some relationship to the rest of the web such that we can extrapolate a case against CSS variables out of them. The relationship is tenuous enough that this disclaimer is included:
The authors who write on this Web site site are probably more careful about the structure and re-usability (and download speed) of their documents than the average Web author and there are indications that the average size of style sheets on the Web is two or three times higher. That is still small for computer code, though. Although it doesn't fit in one window, like the average W3C style sheet, it doesn't take more than scrolling once or twice either.
There's much wrong with this leap of logic: if the real web is at least 2x more complicated, how can we dismiss the clamors of real web developers for more powerful tools? Further more, what's to say that what is or isn't being encoded in CSS is due to to complexity? There are lots of things which we'd like to put in CSS but don't because CSS just can't do many of the things we should expect of it. Real-world CSS is likely to get longer, not shorter, as CSS evolves toward its manifest destiny and allows us to declare property bindings, animations, and all manner of complex layouts for which we currently turn to table elements and layout systems like the Dojo BorderContainer and ExpandoPane widgets. This isn't a foot-note, it's an out-and-out refutation of the proffered case.
We can also do much better than the chosen sample set. A quick
wget of the front pages of the top 20 Alexa sites (to stop short of the porn) reveals a world which the article's sample set bears no resemblance to. Remember, these are only the front pages, as well. Internal pages can be significantly more complex as they trend toward applications and away from relatively static views of data. Here's what I ran to get data to work with:
media:css_stats alex$ ls ./ ../ out/ sites.txt media:css_stats alex$ cat sites.txt http://yahoo.com/ http://google.com/ http://youtube.com/ http://live.com/ http://msn.com/ http://myspace.com/ http://facebook.com/ http://blogger.com/ http://orkut.com/ http://rapidshare.com/ http://microsoft.com/ http://google.co.in/ http://ebay.com/ http://hi5.com/ http://aol.com/ http://google.co.uk/ http://photobucket.com/ http://amazon.com/ http://imdb.com/ http://imageshack.us/ media:css_stats alex$ wget --user-agent="..." -P out -l1 -p -H -i sites.txt --15:05:15-- http://yahoo.com/ => `out/yahoo.com/index.html' Resolving yahoo.com... 220.127.116.11, 18.104.22.168 Connecting to yahoo.com|22.214.171.124|:80... connected. HTTP request sent, awaiting response... 301 Moved Permanently Location: http://www.yahoo.com/ [following] ...
Of these 20 pages, there are only 28 referenced external style sheets (per
wget), likely to speed rendering time. Most of the pages that do specify external style sheets also host them on "static" servers to increase download parallelism and resource usage on front-end boxes. We can already say something about the use of CSS is large, commercially successful websites:
Site authors are going to enormous lengths to ensure that pages load as fast. Therefore, techniques which reduce redundancy and therefore result in smaller style sheets will have significant value to content authors.
Recall that one of the primary drivers behind CSS inheritance, macros, and variables is to reduce the size of style sheets. Just looking at the behavior of real-world page authors at least makes a strong case for techniques to create terse style sheets if not for these specific solutions.
These external style sheets have a median line count of 280, seemingly validating the essay's assertion that the "real world" is 2x to 3x more complicated. But something tells me that's also misleading. Indeed:
media:css_stats alex$ cd out media:out alex$ find . | grep "\.css" > css_files.out media:out alex$ cat `cat css_files.out` | wc -l 7866 media:out alex$ CSS_FILES=`cat css_files.out` media:out alex$ for f in $CSS_FILES; do wc -l $f; done 92 ./i.media-imdb.com/images/SF389ed063874f275ab16e1fef86e6462a/css2/consumerhome.css 419 ./i.media-imdb.com/images/SFf399dbc3948ab005b0ed6e733d294c7c/css2/consumersite.css 59 ./imageshack.us/css/styles.css 138 ./imageshack.us/img/style-def.css 32 ./imageshack.us/img/tooltips.css 122 ./include.ebaystatic.com/v4css/en_US/e573/GlobalNavVjoOpt23_Ebay_e5736892865_en_US.css 128 ./include.ebaystatic.com/v4css/en_US/e577/CCHP_HomepageV4_SLDR_e5777009417_en_US.css 310 ./rapidshare.com/img2/styles.css 86 ./static.ak.fbcdn.net/rsrc.php/102900/css/typeaheadpro.css 58 ./static.ak.fbcdn.net/rsrc.php/104778/css/dialogpro.css 332 ./static.ak.fbcdn.net/rsrc.php/108104/css/ubersearch.css 150 ./static.ak.fbcdn.net/rsrc.php/98481/css/welcome.css 10 ./static.ak.fbcdn.net/rsrc.php/99258/css/webkit.css 2081 ./static.ak.fbcdn.net/rsrc.php/pkg/77/113750/css/common.css.pkg.php 0 ./static.hi5.com/friend/styles/global_1215662072.css 0 ./static.hi5.com/friend/styles/headernav_1214604328.css 0 ./static.hi5.com/friend/styles/homepage_anon_1203011808.css 0 ./static.photobucket.com/include/css/pkgs/homepage_v14.2.4.css 0 ./static.photobucket.com/include/css/pkgs/photobucket_v14.2.4.css 0 ./stc.msn.com/br/hp/en-us/css/54/bluso.css 377 ./x.myspacecdn.com/modules/common/static/css/global017.css 346 ./x.myspacecdn.com/modules/common/static/css/header/siteheader004.css 192 ./x.myspacecdn.com/modules/common/static/css/master.css 853 ./x.myspacecdn.com/modules/splash/static/css/splashv2007.css 386 ./z-ecx.images-amazon.com/images/G/01/nav2/gamma/n2CoreLibs/n2CoreLibs-n2v1-43122._V252271770_.css 1428 ./z-ecx.images-amazon.com/images/G/01/nav2/gamma/navbarCSS/navbarCSS-navbar-53059._V252284495_.css 256 ./z-ecx.images-amazon.com/images/G/01/nav2/gamma/topproductideasCSS/topproductideasCSS-topproductideasCSS-50166._V13960170_.css 11 ./z-ecx.images-amazon.com/images/G/01/s9-campaigns/popover._V255266624_.css
But what about those 0-line files?
ls says there's more there:
8.8K ./static.hi5.com/friend/styles/global_1215662072.css 4.4K ./static.hi5.com/friend/styles/headernav_1214604328.css 2.3K ./static.hi5.com/friend/styles/homepage_anon_1203011808.css 8.8K ./static.photobucket.com/include/css/pkgs/homepage_v14.2.4.css 34K ./static.photobucket.com/include/css/pkgs/photobucket_v14.2.4.css 1.6K ./stc.msn.com/br/hp/en-us/css/54/bluso.css
Indeed, they're all 1-line long and missing a trailing newline char due to the whitespace removal that's been applied to them. The shortest of the files, when expanded for readability, is longer than 100 lines. Clearly counting lines doesn't actually tell us much about the complexity of production-quality CSS – at least not without some normalization. Since most production-level CSS is embedded in the served document then, we should probably have a look at it too and figure out ways to normalize the whole shooting match to determine some sort of "style complexity factor" since it's very much the case that the impact of CSS is not often isolated to individual elements. Indeed, some of the hardest to maintain issues with CSS come from the overall difficulty of knowing what's affecting which element and those rules can come from anywhere. So getting an accurate view of the amount of style that a developer or designer needs to keep in their head at once (the central argument of the original piece) is usually some factor of the total number and applicability of the rules in the page to the elements currently being styled. Therefore, to get a sense of the complexity of the style being applied to a page, it would be far better to know the number of normalized lines of CSS on the page plus a count of the total number of rules applied to the document.
I put together a small python script to do just this. Quickly summarized, it sweeps through documents looking for external stylesheet links,
@import statements, or
<style> tags, parsing the contents of each into a normalized, pretty-printed form. Here's the summary output:
files examined: 17 total # of CSS rules: 9462 normalized lines of CSS: 39999 average # of CSS lines per file: 2352 (mean) 1428 (median) average # of CSS rules per file: 556 (mean) 308 (median) average # of CSS style sheets per file: 4 (mean) 3 (median)
(full output here)
This output comes after removing items from the list which don't have valid index pages (e.g. microsoft.com got wise to my faked user agent) and which included some manually fetched external CSS files that
wget initially missed. Also, it's worth noting that the Google home-page pulls the averages down significantly since they only include 111 lines of normalized CSS per and the home pages for google.com, google.co.in, and google.co.uk are seemingly identical from this perspective and all occur in the top 20.
Never the less, the results are still astounding when compared with the results from the original article. CSS authors who maintain the world's most popular landing pages are contending with thousands of lines of CSS per page and hundreds of rules. This is orders of magnitude more complexity than the initially presented numbers, hopefully dispelling any notion that we could rely on those numbers as the basis for asserting anything but that those in the employ of the W3C and the volunteers which join them are not typical content authors and do not attempt the feats of CSS which are meerly work-a-day constructions for commercially successful websites. Granted, the home-pages of the most successful websites on the internet are also not "normal" (by definition), but they are significantly more representative of where the web is heading and the standards that content authors likely aspire to.
The article's numbers may indeed present a compelling case for not adding CSS variables for the sake of the W3C's content authors, but no such case holds in the "real world" of deployed content.
Upon Further Inspection...
One argument made in the article is that the ability to understand what you see in a style sheet is bolstered by a lack of indirection. This argument is simplistic insofar as CSS is already rife with indirections. From cascades to the order of precedence in style application to the
On this point the essay also contains a rhetorical bait-and-switch which I find distasteful: it dismisses variables because they don't inherently do anything to reduce the lengths of pages (true!) and then argues against macros and inheritance because they create levels of indirection which can be confusing. Inheritance and macro definitions can play a key role in drastically reducing the length of style sheets. In this way, they promote understanding through exactly the same "memory effect" mechanism that is cited as a liability when discussing variables.
Variables, on the other hand, provide an effective and over-due mechanism for consolidating the definition of shared values across style sheets which may be defined in distributed places (say, via a CMS's default template which is later customized by users). For the very-lengthy, real-world styles which occur frequently on the public internet, this ability to cleanly separate the definition of common values into a single style sheet would prove a huge boon to the development and maintenance of sites for which large teams must cooperate on the generation of what ends up being a single page. Style sheets are already long, and the proponents of variables assume this to be true. That variables do not shorten style sheets is not a valid argument against the considerable good that they can do in ensuring that style sheets are maintainable.
The essay dismisses the idea that variable names are (and should be) self-documenting. The argument that a comment would somehow "be better" ignores the reality of todays large style sheets. There isn't a way for rules to effect similar visual appearance on different properties without repetition today, leading to tremendous maintenance headaches.
Modern style sheets are already well beyond the complexity levels which allow us to fit them all in a single screen, and re-using values today requires the exact same looking-in-multiple-places-burden that the essay deems unacceptable in a future with macros. The results for this extra effort today, however, aren't consistent and maintainable rules which can be changed with relatively few updates. Instead we're left with a mish-mash of hard-coded values which are copied here and there, often across multiple style sheets. Adding multiple classes to a single node is also no panacea as it quickly devolves into tens or hundreds of small rules to define what are essentially parameterized constants for a single set of layout, color, or typography decision combinations. These decisions cannot be conveyed through a simple selector but must instead by applied in the right combinations throughout a document directly to elements which required them. Ugg. Even if the original article were to make a cogent case against the need for variables, that can't be extended to a case against inheritance or macro capabilities. Composition is far too difficult and authors are already awash in complexity. Denying them effective, optional tools to deal with this complexity is simply to deny the truth of the web which has evolved.
Cobbling It Together
Perhaps the most disingenuous argument fielded is that the addition of variables in CSS places an onerous burden on the developers of user agents. User agent developers are best suited to know the difficulties and pitfalls in implementing CSS variables and at least one team has decided that not only is it workable, they have authored the spec now under discussion and have implemented several different syntaxes for the feature in parallel in order to figure out what will work best. Were there hue-and-cry from other implementers, I'd be much more sympathetic to this point. However, given the general lack of objection amongst implementers, the long-standing ambiguities in the CSS specifications, the inscrutable choices of box models, and the weirdisms of the CSS in general it seems that we're very far down the path in terms of the complexity required of any implementor. It is probably the case today that authoring a new HTML and CSS rendering engine that will consume the real web isn't a realistic prospect save but for the most well-heeled and motivated of teams today. Adding or not adding CSS variables and/or macros doesn't change that reality.
The arguments against variables and macros/inheritance get weakest when they are taken as a whole. Variables are likely just the first step to a CSS that allows both simple parameterization (variables) and composition (inheritance, macros, etc.). One without the other is weak sauce, and the essay tacitly acknowledges as much by arguing against them in turn (but not in together). A CSS dialect which includes inheritance will allow the specialization of "parent" rules without relying on extra nodes or multiple classes added directly to nodes. CSS with variables will allow for much simpler maintenance and "templating" of complex visual identities. Taken together, these techniques allow for sophisticated CSS authors to stop repeating themselves and get a handle on the thousands of lines of code which they're managing to construct pages today.
Arguing that they are too hard or too confusing simply ignores the deeply painful experience of today's content authoring process. The time has long passed when we can delay progress or claim it "harmful" without proof. Once again, it's time to let the implementations lead and time for the standards bodies to stand aside and cheer them on.