I released a BRS Lab named CuttySSark some months ago. It operated under an experimental idea that fundamentally changes how a front-end developer could approach interaction design. The library generated some buzz on Twitter when Chris Coyier of CSS-Tricks.com tweeted about it favorably. Amongst a humbling number of appreciative tweets, re-tweets, pre-tweets, and un-tweets, there they were, gorgeous as ever: the haters. Now, I can deal with haters --- in fact, I really love them for the sake of provoking thoughtful conversation.
Twitter isn’t a great place for thoughtful conversation, so here I am on the “Internet,” responding to tweets in web log format (a silly thing, but alas). See y’all in the comments! Dukes up (just kidding).
stick. gloves. shirt.
— Mighty Ducks Quotes (@QuotesDucks) December 7, 2012
For those of you who are curious to know: the purpose of CuttySSark is to augment CSS by exposing to it user interaction, similarly to the useful and stateful CSS1/2 :hover
, :active
, and :focus
pseudo-selectors. The JavaScript event model is the vehicle for this, but nothing more than that. You can mess things up with CuttySSark. However, you can also turn your front-end developer life into butter. We hope native user interaction design may follow a similar, but improved model in the future. For now, this is what I have.
Let me back up a tad bit to explain the idea behind CuttySSark, and why I believe it scares some people, including several of my co-workers. CuttySSark allows one to write CSS that interacts directly with the JavaScript event model. Here’s a simple example:
big[on~="click|toggle"] #little { background: transparent; }
Cutty reads my stylesheet and finds this rule that causes the background transparency on #little
to toggle when #big
is clicked. Cutty is responsible for setting up JS events so that the CSS2-compliant selector written in the stylesheet, #big[on~="click|toggle"] #little
, is actually matched at the correct time.
The crucial distinction here: The CSS you write is directly responsible for the style changes, as opposed to JavaScript manipulating styles via the DOM style object.
This approach has the same benefit as class-swapping via JS. I expect we can all agree that it’s useful for styles to live solely in stylesheets and not in JS.
@cbracco @chriscoyier Neat! Not to argue, but isn't this just a messier version of JS? Didn't we stop using the onclick attr for a reason?
— Paul Molluzzo (@PaulMolluzzo) November 14, 2013
Ah, you’ve got me! I don’t want styles to live in JS, but I do want JS-driven events to live in CSS. In all earnestness, yes! Well, I don’t want all events to live in CSS, but I do want the ones related to style-specific changes. I just want my stylesheets to reflect the statefulness of the styles described. It works wonderfully for :hover
, :focus
, and :active
, does it not? I’ve never heard anyone complain about them, and nobody should! They are incredibly convenient because I can simultaneously understand both what style will appear, and also when and where it will appear. Class-swapping via JS obfuscates that very action.
Well, interaction design has pushed beyond these “dynamic/interactive” pseudo-selectors: two simple examples of revolutions in interaction being HTML5’s draggable
and CSS3’s animations, both of which are backed by a suite of JS-driven events. CuttySSark is a polyfill bringing CSS2’s stateful-mindedness into the present.
@chriscoyier I think CSS should be more or less static and JS should be used to control it dynamically. Events in CSS and JS is just messy.
— Ryan (@swap_meet) November 14, 2013
I do agree that there is one idea floating around with CuttySSark that has not been properly addressed. It’s possible that on the Labs demo page I stressed the usage of “event”-driven styles too much. Here I’m stressing the usage of “stateful” style, and events are not states --- they’re typically transitions into states. For example, the Cutty selector [on~=mouseover]
would match the moment the cursor moves on top of an element, but it would still match when the cursor leaves the element. Thus, it’s matching a relatively meaningless state of the element of “having been moused-over.” That’s why I implemented the state
, clear
, toggle
, and once
options within Cutty.
These options allow us to implement well-defined states using events as transitions. I’m thinking a little state-machiney right now. Even though the events represent the transitions (denoted by -->
in a moment), CuttySSark’s options do support the idea of actual statefulness:
once
implements the states of “on” and “off” in the machine[off]-->[on]
toggle
implements the states of “on”, “off”, and “default” in several machines, one of which being[default]-->[on]<==>[off]
clear
allows for a sort of “return to statefulness” by reverting non-stateful style blocks.state
implements statefulness by forcing elements to assume exactly one stated style block at a time.
I genuinely had this in mind! It’s easy to deviate from it, and I understand that you can shoot yourself in the foot by allowing an element to have too many disparate Cutty-induced styles applied to it at once. Of course, any flexible system can be used for evil.
@chriscoyier Is the idea that anything which gets done in JS a lot should be implemented? Not sure of the feature creep potential...
— Chris Bowyer (@chrisabowyer) November 14, 2013
Hmm...I sense an elephant in the room. There is a somewhat ugly corner of Cutty that won’t need to be used most of the time: the support of a rather ugly syntax that allows an event on one set of elements to trigger a different event on another set of elements. It looks like this:
selector1[on~="event1|trigger|event2(selector2)"] { ... }
That actually reads somewhat reasonably (“for elements in selector1, on event1 trigger event2 on elements in selector2”), but I concede it’s an abuse of CSS because it’s a meaningless style block that interacts directly with the event model, and not with any styles.
That said, it can be incredibly useful for simple UI elements. I was thinking about all the different UI elements that could be created simply by manipulating styles without reference to any sort of programming logic once a user’s interaction with the DOM were exposed to CSS.
The last step in exposing user interaction to CSS was to allow interaction with one element to affect the state/styles of a separate, non-child element. Thus, that’s precisely why this feature exists. Again, the purpose here is not to mindlessly force a random piece of JS into CSS, and of course I do not support extending JS functionality into CSS. Rather, my purpose is to expose user interaction to CSS beyond CuttySSark’s grandparents, :focus
and :hover
. JS is merely the vehicle for that.
The bottom line here is that CuttySSark is a simple tool loaded with implications. I like to think with Cutty we’re one step closer to a non-Frankensteined incarnation of CSS, which has kept up with user interaction beyond mousing over and out.
Cutty Shark!