One of the coolest concepts in cujo.js is the introduction of Object-Oriented CSS into the Views and Widgets. I’ve seen several engineer’s eyes glaze over when I mention OOCSS, but don’t dismiss it as just a rehashed retelling of how to structure your CSS. OOCSS is a very powerful and efficient tool, especially when used in conjunction with Object-Oriented JavaScript and inheritable HTML templates.
I’d love to dive right in and show you how it all works in cujo.js, but you’ve got to have a firm understanding of OOCSS for any of it to make sense. Let’s get started…
Basic principles of OOCSS
Where better to learn the basic principles of Nicole Sullivan’s OOCSS than from the source? I highly recommend you watch the slideshow and read the FAQ. Here are some of the main points:
An “object” in OOCSS is an HTML fragment and its associated CSS classes*.
You extend objects by applying multiple classes to its root element.
You must follow some basic guidelines:
Separate structure from skin (styling).
Separate container from content.
Don’t use ID attributes to define CSS rules.
Use CSS “hacks” for targeting and fixing browser quirks.
*Nicole alludes to some JavaScript associated with these OOCSS “objects” (a hilariously surprising assessment from the perspective of a JavaScript engineer who might think of JavaScript as the primary language and of CSS as secondary).
Nicole includes several other guidelines, as well. All the guidelines can be summarized into three major categories: 1) guidelines to help reuse objects and CSS classes, 2) guidelines to prevent unnecessary specificity increases, and 3) guidelines to allow OOCSS principles to work in ancient browsers.
The ultimate benefit of following OOCSS principles is optimal reuse of CSS rules and OOCSS objects.
For an excellent and detailed example of OOCSS in action (and a very slick use of CSS3), jump over to Brian Cavalier’s blog post, Building a digital clock with OOCSS and MVC and come back.
OOCSS inheritance
If code reuse were the end of the story about OOCSS, it would certainly be no small achievement, to say the least. Nicole has done an amazing service to the web industry, especially to those whose main job is to wrangle CSS. But little did she know, she also planted a seed of inspiration in several JavaScript engineers’ heads, mine included. I had been already trying to form solid ideas around very similar CSS patterns, but couldn’t find the right words or evidence. After watching her speak live at TXJS 2010, things started to become crystal clear — especially when she started talking about reusable objects.
One of the most common methods to reuse code is through inheritance. In classical object-oriented languages, classes inherit attributes and behavior from ancestor classes. The classes are then used to construct objects. In prototypal languages (such as JavaScript), objects inherit attributes and behavior from ancestor objects. However, in OOCSS, objects inherit attributes and run-time state from ancestor objects.
Read that one more time: “…objects inherit attributes and run-time state…” We’re not talking about some static, compile-time concept as with classical inheritance. And we’re not talking about inheritance that happens during object construction. We’re talking about run-time, baby!
As an object changes at run time from one state to another, so too do it’s descendants. Or, conversely, as an object’s ancestors states change, so too does the object. Brian and I talked about this concept and dubbed the term, “whole state”, to describe the object’s current state combined with the states of its ancestors.
Let’s jump right into an example to better grasp this. Here’s a simple HTML snippet from a facetious “club” project:
<section class="club-view club-hawt-view"> <ul class="club-list"> <li class="club-item club-rock-item">1st Item</li> <li class="club-item club-disco-item">2nd Item</li> <li class="club-item club-pop-item">3rd Item</li> </ul> <button class="dance-mode-selector">Let's do Disco!</button> </section> |
Notice the name-spaced css classes (using dash-notation to be friendly to HTML4 strict documents). While not important to this discussion, name-spaces are important to protect your code from name conflicts in large projects, especially if not all of the CSS uses OOCSS principles!
More importantly, notice the classes on the root element of our topmost “object”. club-view
and club-hawt-view
describe static classes in the classical or prototypal sense. club-hawt-view
is a specialization of club-view
. Underneath this club-view
object (as we’ll call it for simplicity’s sake), we have other objects: club-list
and club-item
. club-item
has three different specializations, as well: club-rock-item
, club-disco-item
, and club-pop-item
.
Note that we must specify both the base (ancestor) and specialization (descendant) classes on the element. This is because CSS does not specify a way to declare the inheritance relationship in the stylesheet. This is not a limitation of CSS, in my opinion, just an implementation detail.
Interestingly, Nicole calls for declarative inheritance in her slides. This would allow the designer to specify the link to the ancestor class in the stylesheet, rather than in the HTML. Thus, only club-hawt-view
would need to be specified on the object since the stylesheet would declare the link to the ancestor, club-view
.
(Some other projects have implemented compile-time solutions to provide declarative inheritance. However, declarative inheritance in the stylesheet may do little except save some bulk in the HTML, imho. I’m on the fence about it. It feels like it’s an idea invented out of basic misunderstanding of CSS inheritance, but I can’t really see any significant down-sides at the moment, either. In fact, if used correctly, it may help clarify the difference between specialization CSS classes and stateful CSS classes in the HTML.)
OOCSS state
Now, imagine that we want to place our club-view
object into disco mode when the user clicks the button. In disco mode, we want to highlight certain objects and de-emphasize — or even hide — others. For instance, we don’t want to show any club-rock-item
objects. (Cuz rockers don’t do disco.) We could set them to display:none, in this case.
In a noobish implementation of this behavior, we would simply catch the button’s click event, query the club-rock-item
elements, and hide them. This is seductively easy (and dangerous) in jQuery:
$('.dance-mode-selector').click(function () { $('.club-rock-item').css('display', 'none'); }); |
or dojo:
dojo.query('.dance-mode-selector').onclick(function () { dojo.query('.club-rock-item').style('display', 'none'); }); |
The less noobish of us know it’s a lot more cpu-efficient and flexible if we did this using CSS classes instead of manipulating the nodes’ styles directly. Let’s add the following CSS rule and change the click event handler to use it:
.club-disco-mode .club-rock-item { display: none; } |
dojo.query('.dance-mode-selector').onclick(function () { dojo.query('.club-view').addClass('club-disco-mode'); }); |
The resulting HTML would look like this:
<section class="club-view club-hawt-view club-disco-mode"> <ul class="club-list"> <li class="club-item club-rock-item">1st Item</li> <li class="club-item club-disco-item">2nd Item</li> <li class="club-item club-pop-item">3rd Item</li> </ul> <button class="dance-mode-selector">Let's do Disco!</button> </section> |
Notice I put the club-disco-mode
class on the root object, not the club-rock-item
objects (more about this in the next section). Changing the CSS class instead of direct DOM styling puts the task of deciding how to handle club-disco-mode
in the hands of the CSS designer where it belongs. For instance, once she’s seen the button jolt upwards (as it would when the club-rock-item
object disappeared), she’d likely throw up a little in her mouth or have a mild seizure induced by this severe UX faux pas! Then she might mute the colors instead of removing the element from the layout.
The beauty of this is that there’s no need to mess with the JavaScript to make this change. The task of deciding styling and layout for this state change is defined entirely in the CSS. In fact, the only dependency between the CSS and the JavaScript is the coordination of a single class name, club-disco-mode
, on the root element of our object. You can think of this class name as a message from the JavaScript to the CSS, telling the OOCSS object that it is in a new state. We’ve essentially just decoupled the JavaScript from the CSS using a classic method used in object-oriented programming: message passing.
Not impressed so far? This is just good CSS practices cast in the light of classical OO, you say? Ha ha, don’t worry. We’ve only scratched the surface. In a subsequent blog post, I’ll show you how cujo.js abstracts the concept of state changes, allowing both CSS (style and layout) and JavaScript (behavioral) state changes to execute in parallel with a single line of code.
But first, let’s dig a little deeper into run-time state inheritance…
OOCSS run-time state inheritance
In our “club” app, we can also treat the repeated club-item
elements as objects, too. When we change the state of the root club-view
object to club-disco-mode
, we’ve also changed the state of all of the club-item
objects. We can take advantage of this by declaring OOCSS rules like the one below. This rule is just like the earlier rule, but the style declarations have been changed to something less seizure-inducing to somebody with UX sensitivities:
.club-disco-mode .club-rock-item { background-color: #ccc; color: #777; } /* grayed-out */ |
You could read this as club-rock-item
objects under the state of club-disco-mode
. If we wanted to be even more explicit, we could write it like this:
.club-view.club-disco-mode .club-rock-item { background-color: #ccc; color: #777; } /* grayed-out */ |
This translates to club-rock-item
objects under club-view
objects in the club-disco-mode
state. Here we see how the club-rock-item
objects inherit the state of their ancestor(s) and how we can define the style attributes of those objects in response to that state. In the more explicit variant, we’ve also increased the specificity, which may not be desirable in all situations, so the shorter variant is also acceptable as long as it can’t be interpreted ambiguously.
So, why did I declare the rules this way? Why didn’t I change the state on the club-rock-item
objects instead of the club-view
object? Because the button’s stated purpose is to change the state of the entire object, not of only the club-item
objects! Too often, we JavaScript engineers concentrate too much on the task at hand (manipulating the club-rock-item
elements), not the semantic meaning of the user’s action (to change the state of the club-view
object).
Let’s revisit the club-hawt-view
specialization class to better illustrate an example of why this is so important. When this class is applied to our object, we potentially inherit a whole new set of CSS rules. One of these rules could define an entirely different layout or a different styling. Maybe in a club-hawt-view
we’ve turned up the heat a bit:
.club-hawt-view { background-color: #fa7; color: #500; } /* red on orange! HAWT! */ |
It just wouldn’t fit to de-emphasized the club-rock-item
objects with a gray background, anymore. The gray and orange clash. Instead, when we’re in the club-disco-mode
state, let’s embolden the font on the emphasized objects and just change the font color on the de-emphasized club-rock-item
, not the background. Let’s also add a dotted border around the whole object (yah, yah, I know this is getting really damn ugly, but hey, I’m an engineer):
.club-hawt-view.club-disco-mode .club-disco-item, .club-hawt-view.club-disco-mode .club-pop-item { font-weight: bold; } .club-hawt-view.club-disco-mode .club-rock-item { background-color: transparent; color: #777; } .club-hawt-view.club-disco-mode { border: 1px dotted pink; } |
The key point is that we didn’t have to change the JavaScript to deal with the specialized, club-hawt-view
object. We still just passed the same club-disco-mode
message to the OOCSS club-view
object from the JavaScript in response to a button click:
dojo.query('.dance-mode-selector').onclick(function () { dojo.query('.club-view').addClass('club-disco-mode'); // still the same exact code! }); |
OOCSS decreases risk
This has been a simple example, but you can start to imagine why using JavaScript to programmatically change styling starts to get ugly. Here’s what the code might look like if we used JavaScript instead of CSS:
dojo.query('.dance-mode-selector').onclick(function () { dojo.query('.club-item').forEach(function (item) { if (dojo.hasClass(item, 'club-disco-item') || dojo.hasClass(item, 'club-pop-item')) { dojo.style(item, 'fontWeight', 'bold'); } else { dojo.style(item, { backgroundColor: 'transparent', color: '#777' }); } }); dojo.style(this, 'border', '1px dotted pink'); }); |
This is not reusable code, nor is it very maintainable once you start getting into more complex, real-life projects. Brian pointed out to me that the general complexity of the situation can be summarized as O(n^m), where n == the total number of CSS classes on a node and m is the number of ancestry levels we may need to manipulate. If we’re handling just 3 CSS classes on 3 levels, we’ve got up to 27 separate cases to consider in code.
Worst of all, we’ve inextricably tied our button and our club-item
elements together. If we were to suddenly need a variation of the club-view
objects without the club-item
objects at all, we’d be forced to branch yet again.
As Brian said in his post, declarative code — such as CSS — is inherently less risky to modify than procedural code.
OOCSS in ancient browsers
The astute CSS developer will have identified several problems with all of the CSS I’ve shown. Specifically, none of it will work in IE6 at all! Combination class selectors (.club-hawt-view.club-disco-mode
, for instance) and transparency weren’t supported in IE until version 7. Not to worry, cujo.js fixes those automatically. It also fixes several other CSS2.1 and CSS3 shortcomings in IE. cujo.js doesn’t come close to bringing IE up to CSS3 specifications, though, so don’t get too excited. cujo.js only fixes IE enough to allow OOCSS to work to its fullest potential while also removing the dependencies between CSS, HTML, and JavaScript. Separation of concerns has always been a major goal of CSS, but only CSS3 finally fulfills it. More on that in yet another future blog post.
[update]
For years I thought IE6 didn’t support combination class selectors! People are telling me that they work as long as you order the classes correctly (.bar.foo {}
versus .foo.bar {}
). I must always order them the way that doesn’t work. I’ll do some further testing and verify.
[/update]
You likely also noticed that Brian is using CSS3 transitions in his project. Transitions are a critically powerful tool in any UX designers toolkit. Unfortunately, IE and Firefox still don’t support transitions (as of September 2010). No biggie, cujo.js fixes that, too. We’ve even extended transitions to include more popular timing functions such as bounce, elastic, sine, etc. We’re also investigating other, more advanced types of transitions to emulate common use cases that don’t fit the CSS3 transitions model at all.
For instance, transitions alone can’t animate an element being tossed into the trash. Too often the element being deleted and the trash icon don’t share the same offsetParent or there’s an ancestor with overflow:hidden somewhere between. For situations like this, you’d typically have to append the node to some common ancestor (likely the body element) and then animate it from the original location to the trash icon. That kind of sequence comes in handy for accessibility-friendly alternatives to drag-and-drop — as well as a few other use cases. So, we’ll be investigating ways to allow the CSS designer to take control of complex transitions like these without tinkering with the engineer’s JavaScript.
Still not convinced of the benefits of OOCSS? Next we’ll see how to apply it in a client-side MVC architecture. OOCSS becomes even more powerful when you combine it with view-controllers based on OOJS and ultra-simple, inheritable templates I’ve dubbed OOHTML.
What do you think so far? Does OOCSS make sense? Have you already used it in an MVC-based environment? Let me know!
Pingback: Tweets that mention cujo.js — OOJS, OOCSS, and OOHTML — Part 1 | Unscriptable.com -- Topsy.com
this is going to be really fun, watching the jsmafia run wild with css. i am going to liken it to when i went off the deep-end with jQuery.
oocss is very nice. it really opened my eyes to alot of things.
one thing i love is targeting each browser that you need to, to maximize cross-browser compatibility. these are “hacks”…i guess, but i’ve heard so many things called “hacks”. at my last job, negative margins were “hacks”…(side note: why are hackers cool and held in awe, but a css “hack” is a bad thing? sider note – considering css isn’t a programming language, is it really “hacking”)….if you understand what the hack is and what it does, you’re simply using the rules that were built into the browser. now i’m rambling. so on that note, idk how many fixes you have for IE(s), but if you are still working on future releases, don’t even sweat that stuff; as long as you can target the IE property. ok check it out, so the example with background-color:transparent; right after that declaration you just redeclare it with _name{background-color:#000}. that’s exactly whats in oocss.
i admit, i disliked it at first simply because of it’s naming structure; it’s quite contrary to naming conventions based on “function” or what have you. but then i got out of middle school and realized what was really going on. i will say the markup is not as lean as i like it, but wtf do i know.
i’m really stoked that ya’ll have started playing with this. expecting fun things.
As far as I understand it, IE6 only applies the last class when you specify multiple classes. So:
.bar.foo .child {…}
Will be applied to .child elements under all .foo elements, whether or not the .foo is also a .bar.
But who cares about IE6, really? 😉
Unfortunately, HB, some of us are still writing web apps for use in large corporations. IE6 compatibility is a must-have “feature”. 🙁
I love the principles here and for a while I have been doing things like adding a ‘fullscreen’ class to a container and defining how the elements in the container are affected by that change in CSS. The only place I get lost with this is… isn’t there some point where you have to let JS handle which objects are in view? Otherwsie you end up with eeeverything in the DOM at once with all the states being manipulated by CSS. Which is conceptually lovely but performance-wise…not lovely. Be interested to see your thoughts on this.
Hey Nick,
You definitely have to modularize somehow. A widget-based architecture helps. In-browser MVC also emphasizes modules (a.k.a. the Views are basically dom fragments). cujo.js supports a state() method on the View-controller (a.k.a. the JavaScript behind the View) which allows simple or sophisticated state manipulations that translate to CSS classes being applied/removed to the root node of the View. Extremely simple example:
myView.state(‘fullscreen’, true);
This could trigger styling and layout changes in CSS, including transitions, as well as behavioral changes described in JavaScript by hooking onto the onStateChange event handler.
I worked on a jQuery project last fall and instituted a fairly simple methodology for modularizing the application into widgets we called “components”. Any jQuery devs have any feedback about how they like to modularize the DOM?
Yeah as I thought you have to draw the line somewhere, and the widget/module boundary seems a good place to do so. The high-level idea of view state on the view controller sounds good to me too. Cheers. Looking forward to more on OOCSS and Cujo. 🙂
You are trying to use a band-aid to treat a decapitation. A real inheritance or mixin mechanism is something that needs to be addressed at the standards level. I would like to bring up Lesscss, I think that server side CSS generation is a step in the wrong direction, but it is a good example of the kind of solution we should be striving for.
Hey Mike R,
There’s nothing in this post that isn’t standards-compliant. The standard method for declaring CSS inheritance is on the node:
To a classical OO dev, this may seem as ugly as a decapitation at first glance, but is it really? This is a perfectly valid mechanism for declaring inheritance, imho.
— John
I’ve always had a difficult time organizing my CSS. I’d add rules here and there just to get things to display correctly and usually ended up with CSS rules which were only applicable in edge case scenarios. OOCSS definitely helps you think twice about these ‘once off’ rules and helps the developer think more about reuse of CSS rules. I don’t think it’s a silver bullet in terms of cutting down on the overall size of your CSS file, but it definitely helps focus the mind on rule reuse. Looking forward to more OOCSS/cujo posts!
Maybe I should be more clear, I’m not criticizing your approach, it is very similar to the jQuery-ui theme system. I hate the JS side of jQuery-ui, but compared to the other toolkits I have worked with it is signifigantly easier to make custom widgets and page elements blend in with existing jQuery themes.
The downside to these OOCSS aproaches is that elements can end up with a large number of classes. This hurts readability and makes refactoring css structures.
I think the upside to OOCSS outways the downside, but I think that changing the CSS specs can solve both issues.
If css supported mixins or class inheritence we could have class strings that look like “house” instead of “widget scrollable building house”.
@Mike R I get what you’re saying. 🙂
@mike how does classitis hurt readability? from a dev’s pov? just curious. i am not a fan of a shit ton of classes and verbose markup, but this is a really slick setup dude. @stubbornella threw it in place @ yahoo! with YUI squad and its really performance oriented. she’s at facebook now and i’m willing to bet anything they start rocking it soon.
as for browser support, it’s quite simple: the more compatible you bake in, the more accessible it will be to a broader audience. i’m not advocating making everything work in IE6 everytime, but if you can just knock out a fix or keep stuff @ a minimum, it’s all in best-practice.
@J. Albert Bowden II
Normally I’m only interested in the end class in an inheritance hierarchy or have a pretty good idea what a class inherits from, so I don’t want to have to read a listing of the entire class history to get to the class I am interested. I find this especially problematic when inspecting documents at runtime, since the class string can change, or when the class would require multiple inheritance hierarchies.
Hi John, If you extending and covering the gaps in browsers, why than not to cover advanced cases and use own extension of CSS? For example, to cover back-referrence: if trash basket has something inside…
Or local namespaces to insulate CSS inside of template it belongs to?
There are quite a bit of alternative to CSS selectors and their applications.
Implementation than will need to match destination platform. As a side effect, better efficiency due to best match for applied platform(browser version).
CSS of any version is a compromise between usability for developer and implementability for browser. The performance in that case even not counted.
It’s tough to find the right balance. We want to separate styling (how the trash animation looks) from behavior (what action initiates the animation and what happens when it ends).
Namespaced CSS is certainly recommended, but I doubt we could enforce it! Unfortunately, not all devs understand its importance enough to place priority on it. (“it’s too ugly.” “it’s too much to type.” “I hate typing all of those dashes.”)
I’m not sure it even makes sense in the larger picture. There’s a bit more to the OOCSS / MVC integration that I haven’t shown yet. Let me know what you think after the next blog post. 🙂
I’m all for OO, namespacing, and better-organized CSS. However…
What is the point of club-list and club-item? Isn’t that a ‘classitis’ way of saying club-view > ul and club-view > ul > li ? I’d prefer the actual element tags, they tell me much more about the HTML structure. If you insist on classnames, then why not use ul.club or li.club? Tagging things with -list and -item seems verbose and unnecessary.
Hey Charles,
I hear your concerns about “classitis”. Sometimes it feels like overkill. Keep in mind that I didn’t want to bog down the blog post with an overly-complex example.
Also, one of the benefits of OOCSS — and specifically of using class names instead of element names — is to be able to reuse the rules for more than one block of HTML. Using element names stymies that effort quite a bit.
I typically use class names down to the level at which I don’t see any more OOCSS objects: nothing below this level can be seen as reusable or stateful. Using classes below that is definitely classitis. 🙂 Well, I take that back. If there can be more than one variety of a specific element, say two types of link, then class names are often the best way to differentiate them. For example: A.sponsored {} and A {} (not sponsored).
We’ve been using OOCSS unkowingly for months 😀
IE6 will only apply the last class in the rule, so
.foo.bar { color:blue; }
equals
.bar { color:blue; }
that can cause quite a mess.
I’m not saying rules can’t be used for more than one block of HTML. I’m saying that if when making an element-specific rule, that it is more concise and useful to use the element name (li.classname) instead of describing the element in the classname (.classname-item).
When using a rule for many types of elements, it shouldn’t contain the element type in the classname. If I see .classname-item I am expecting a li, not a div. Also, using a div as a list-item is not semantic.
I can also see that using hierarchal selectors can be limiting (.club-view > ul > li). But when using OO-style CSS then .club-list is ALWAYS a child of .club-view, which makes .club-view > ul a more descriptive and concise choice. Otherwise if it’s going to be used in multiple places, then it shouldn’t be namespaced or described as a child of .club, again it should be a ‘global’ style.
Nice read indeed, thanks!
One question: what is your reason to use the class rather than the tag ?
Semantically “list item” would fit perfect IMO.
sorry, in my previous post I used angle brackets. It should red:
One question: what is your reason to use the class “club-item” rather than the tag “li”?
Semantically “list item” would fit perfect IMO.
Hey Juergen,
It will hopefully make sense in the next article when the discussion will move into MVC concepts.
I’ve also read that using stricter right-hand rules improves performance. Considering most modern browsers place special significance on class names, I would tend to believe that using class names is surely faster than tag names in most cases.
I have not tested this hypothesis, though.
i’ve been using OOCSS for 2months 😀
IE6 will only apply the last class in the rule, so
.foo.bar { color:blue; }
equals.. But now i will do with firefox and i do have problmes..