Why Stylesheet Abstractions Matter
chriseppstein.github.com
chriseppstein.github.com
Straight off the bat, going from CSS/Blueprint to Sass/Compass got rid of ~300 lines of styling, simply because Sass is so much more expressive.
Then we went through the code and extracted all the color literals and stuck them in a variables file. Instantly we were able to play with site colors without search/replace drama. The stylesheets themselves also got far more readable, since you never have to work out in your head what a particular hex string probably meant. Little things like that remove friction from the dev process, and are totally worth it.
Of course, once we had all the colors in one place, it became obvious that we had, for instance, 4-5 different oranges all within 15% of each other. We kept the variable definitions, but made them all the same base color.
We repeated the same process with font sizes.
Finally, we went through all our markup and evicted the Blueprintisms, moving them to the stylesheets via Chris' Blueprint Compass mixins. This was more than a "semantic vs. visual" hygiene win. Playing with column widths involved finding where Blueprint classes were passed in or coded into markup. Now they're right there in the CSS, where you expect them to be.
We've got tons of opportunities to reduce the stylesheets further by macro-izing or mixin-izing, but just by transliterating our code from CSS to Compass we got a big enough win to be happy for this dev cycle.
Can't recommend Compass highly enough. Great work, Chris.
We've got about 250 template files total (including partials), and a couple thousand lines of stylesheet.
I have always found it easier to avoid bugs when parsers are dealing with canonical forms. In other words, make the browser support the absolute minimum syntax required to achieve every effect in CSS. Anything that's merely "syntactic sugar" should be handled at higher levels, and then "compiled down" into raw CSS.
This restriction not only makes it easier for browsers to agree, but it means that you're only likely to find quirks in your higher-level tools: which, importantly, are outside the end user's domain. Bad tools can be replaced, or you can adjust your flow to insert post-processing steps that fix the output. You don't need as many "debugging tools" because you can simply examine the generated files to tell if something was interpreted correctly (whereas, if a browser isn't seeing things the way you think, good luck figuring that out without extra tools).
span.fl,
span.a,
a.link,
cite { color: #ef88bb; }
body, div.leftnav, div.logo { background-color: #333; }
You're also supposed to rely on the cascade for fonts and stuff: set them once on the body and then let all descendants inherit them.There're some real problems when you want to set, say, the border color of one element to the color of a bunch of others, but a lot of the CSS maintenance problems I see (and have written ;-)) come from developers just going through the list of elements and writing the properties for each. The cascade was supposed to save you from this; CSS already has a pretty powerful abstraction mechanism.
The single-rule output mode of Sass is an output optimization mode we plan to add to sass for runtime performance. You should write code the way you think about things and let your tools do the heavy lifting for you.
This is a problem with any sort of abstraction. When you write a function in normal code, you duplicate the function name and call signature in exchange for centralizing the body. In Sass, you're presumably duplicating the variable name in exchange for centralizing its definition. The same goes here, except s/variable name/selector/.
Most websites have far fewer different text stylings than they have element types. I'm arguing that this is a better direction to point the problem.
(I'm also not arguing that abstraction frameworks like Sass are a bad idea, but that you should understand how CSS works before you reach for a framework. I suspect that it never occurred to a lot of folks that they should have long lists of selectors and short lists of properties instead of the reverse, because that's not the syntactic cue they get from the language.)
I would also like to point out that this post is not an advertisement for compass or even Sass. It's a rebuttal to the people who think any advancement in stylesheet technology is unnecessary. Sass is an implementation of these ideas and compass shows their power in action. But it really is an argument for a new approach.
and to be honest since I dont find css that hard to manage those tradeoffs are enough to put me off using one.
also worth mentioning css variables have been introduced, just waiting for ie? now
So while I accept these as criticism of Sass, I do not accept them as downsides of abstraction.
BTW, Sass will emit comments to your CSS to help you track down the original source of your styles.
Nevertheless, I think I will add them to the list of downsides, because I don't think we'll have wide browser support for "Abstract Style Sheets" any time soon.
But I've not tried it yet and it's not provided by the Sass team so YMMV. It probably doesn't support the most recent sass syntax.
Here's the deal:
* Raw CSS looks exactly like the raw CSS you always had.
* Sass CSS looks like the raw CSS, but is 1000x more readable.
So, the only problem I've noticed is the throbbing pain behind my left eyeball that I get when I have to look at "real" CSS anymore.
(Yes, I do have to search for selector names in my CSS instead of literally jumping to line numbers, but my workflow was never very line-number-centric to begin with.)
For example:
.box{define only properties that you
do not want to
change from box to box
}
.boxColors{background:#fff;
color: #f60}
.arial13{font-family:arial;font-size:13px
<div class="box boxColors arial13"></div>
This way your classes can be used as 'functions'. As a rule, define typography and colors and opacity this way and you can keep it simple.CSS was developed as an abstraction to HTML. Any abstraction to the CSS other than adding pre-processors would create serious integration problems with the DOM model and JavaScript. (See a good discussion of this at http://people.opera.com/howcome/2006/phd/#ch-problems by Håkon Wium Lie the original developer of CSS).
Any productivity pre-processors our our business and not of the spec developers.
Instead, I'd rather have CSS classes each represent a semantic attribute of the element being styled. So instead of <div class = "box boxColors arial13">, you might have <div class=tabbedPanel>. In your stylesheet, you style tabbedPanel with the appropriate background, border, font, etc.
Also don't neglect the value of containment selectors - if you want to style all tabbed panels a certain way, but only if they're in the main results, you can do:
#results .tabbedPanel { ... }
No need for an extra CSS class on them.However, on large sites where, multiple people might be publishing pages with slight variations, it is preferable NOT to touch your CSS too often. The multiple class method gives you some means to control it. It also adds tremendous flexibility for libraries (see jQuery UI's method of handling multiple classes for styling widgets).
Naming your class="tabbedPanel" has added no semantics to your contents and there is no such thing as 'a semantic attribute' defined nowhere. It is just a good naming convention that helps the developer and the designer. Simply there is no semantic meaning to a <div> it is just a container.
How would you handle two tabbed panels, one that is red and one that is blue?
Why is one red and the other blue? Surely there's some functional difference between them? I'd rather call them <div id=hot class=tabbedPanel> and <div id=cold class=tabbedPanel> if that's what they're really representing.
I have nothing against multiple classes - I've written a fairly-well-used JQuery UI Combobox plugin, and I follow the normal JQuery UI conventions for class names there (ui-combobox, ui-combobox-item, etc.) I do have something against replicating typographic conventions as class names - note that it's class=ui-combobox-item, not class="displayblock height1em border1pxsolidblue fontweightbold".
<div class="box hot"> and <div class="box cold">, hot is selected and cold it has been dropped in a 'recycle' container.
I also try to minimize id's, for example I could have <li class="cold"> as well.
I do agree with you that one should not just map all the CSS attributes into classes. Perhaps my example was not a good one. However, three or four additional sets of classes, has increased my own productivity, especially during development. I keep a partial CSS file with 5, 6 generic sets. Most large newspaper sites use this method. It all depends in what one needs to do. In this method the style sheet is 'more abstracted', it does not know about a box.cold. If you skinning a wordpress template, you better off to offer the box.cold in the stylesheet, but then you must provide a second style sheet to offer the box.hot! This method also allows a bit of presentational flexibility for new page designs, without playing with the main CSS files or adding another CSS file. Somewhere, along the line there is a golden line I guess.
The application of multiple classes to an element has nothing to do with the "Cascade". Your classes should describe their meaning, not their appearance. CSS was created to abstract away the appearance. Sass makes CSS more "CSSy" in that respect.
In the end, built-in browser support for a higher-order stylesheet syntax will be driven by increasingly complex cross-browser issues, over-the-wire transfer of complex stylesheets and rendering-time performance issues.
It could be the case that a few simple extensions to CSS would enable css preprocessors to do their job better, I have some ideas about that and will post them eventually.
I build skinnable sites, where there are multiple different looks for identical markup. The approach above would fail horribly at doing this. Markup should be semantic, a div with a class header or footer is semantically identical to a header or footer tag.
Markup is also quite often tightly coupled to code and much much harder to change than CSS, so this approach fails there as well. Blueprint takes this approach, and I think it's just wrong, this is not how CSS should be used.
What would be really neat would be a syntax to be able to have CSS classes inherit from other CSS classes like mixins so that you could build that header style by mixing in several selectors. Then you could use the above approach without corrupting the markup with style information keeping the look isolated to the CSS file. I see SASS provides, that alone makes it worth looking into.
Tell that to a Flash developer. This is one of my pet peeves with Flash sites. No interface standardisation.