My new project: Tact, a simple chat app.

CSS3 transitions and their language design problems

June 08, 2010

I played a bit with CSS3 transitions today, just to understand the basics. And after getting into the more complex territory of transitioning multiple properties, I came across some strange syntax and language design that I think is counter to the spirit of CSS.

But let’s not get ahead of ourselves.

The basics of transitions

On the surface, CSS3 transitions are a great idea, moving presentational logic from Javascript to CSS. People have long used Javascript to animate CSS properties like opacity, position and what not, and CSS transitions basically lets you do the same without Javascript and much more compact syntax.

Also, implementing transitions is harder than many people think. You have to think about things like, what happens if another transition is invoked midway through the previous one and what not. CSS transitions promise to bring some consistency to this space.

The spec is W3C working draft from December 2009 and the latest draft from April 2010, that do not seem to differ much upon skimming. (I didn’t read too thoroughly.)

Transitioning one property

Look at this simple example. Just put the cursor in the textbox and see the transition, and take it away to see the transition again. (I implemented it this way so that it would work on the touch devices. And all these examples work on latest stable versions of Chrome, Safari and Opera, iPhone and iPad, and will eventually work with Firefox. IE has so far decided to ignore the transitions party.)

The operative piece is just this one line of CSS:

-webkit-transition: left 0.2s;

(And its various copies for other vendors and eventually CSS3 without prefix.)

All this is telling is, “animate the ‘left’ CSS property over a duration of 0.2 seconds.” Now, whenever the “left” property of the corresponding DOM element changes, the animation kicks in.

This is all really nice and straightforward. There is other stuff like easing functions that are cool but not necessary for this post, look them up on your own.

Transitioning multiple properties

Now, let’s crank it up a bit. Let’s transition multiple properties, and for the kick of it, let’s also say that these transitions should take a different time for each property, and the timings should be different in both directions.

Sure enough, doing it is not much more complex than the previous example. Check out this example for animating multiple properties. In one direction, the background color animation takes 2s and moving takes 0.2s; when going back, it’s the opposite. CSS got a wee bit more complicated, but not really that much.

“Hey,” I can hear you ask. “Why are you using transition-duration and transition-property separately? Why not use the shorthand like in the simple example, and save a bunch of newlines and typing?”

Excellent point, my friend. This is exactly where I wanted to get to.

The problem of “transition” shorthand for multiple properties

I don’t think shorthand works well (or at all) for multiple properties. Here is my attempt which, quite frankly, I’m not sure what it does. Everything just seems to take 0.2s, the 2s value is ignored. On one hand, the spec has examples where you can have multiple values for timings. And on the other hand, it says…

The first value that can be parsed as a time is assigned to the transition-duration. The second value that can be parsed as a time is assigned to transition-delay.

Either the spec is broken, browsers’ implementation is broken, I’m just too stupid for it, or any combination of the above. If you can explain this, please do.

Well, meh. Not using the shorthand is an annoyance, but something we can live with. But there is a bigger problem.

It is not possible to break the transition attributes for a given element into multiple CSS classes

To me, this is the biggest problem with this spec. As far as I can tell, it is not possible to have transition attributes for a given element span multiple CSS definitions. Note that my examples follow this: “popup” is always one class. But, suppose I wanted to do something like this:

<div class="popup smooth-fade from-left">This is a popup that fades smoothly
and animates in in from the left edge of the screen</div>

.popup {
    opacity:0;
    left:0px;
    position:absolute;
}

.smooth-fade {
    opacity:1;
    transition: opacity 0.4s;
}

.from-left {
    left:500px;
    transition: left 0.8s;
}

Now, to me, this would be a very natural way to write the CSS because you would keep the final value of the property together with the spec of how it is supposed to be animated. But, like I keep saying, it is not possible. Any new “transition” property value, as you would expect from CSS cascading, overwrites the previous ones.

To me, this is counter to the spirit of CSS, whose very essence is that you can break your style into multiple pieces, and the cascading rules, well, cascade to compute the final layout of the element. But here, the transition rules (no matter if I want to use the shorthand or the transition-property long form) are always hardwired to one element. God forbid if some other rule somewhere in the cascade sequence has a different idea about them.

How to fix this?

It is entirely possible that I misunderstood something and what I say is not possible, actually is. This would be great. But on the remote event that I am indeed right, the root cause of this problem is, of course, that transitions are a special meta-element. Unlike all other CSS properties, they do not apply to the element, but to some other CSS property of the element. In that respect, the transitions are quite special and unlike any other CSS element that I know of. Yet the spec still tries to rape them into something that looks like common CSS, and then runs into this kind of trouble.

Now, I am sure the spec writers and implementers are all smart people and have their own reasons. Not least of which, I’m sure, is parser compatibility. But let’s throw that out for a second and imagine what would be the most natural way to write the transitions? How about just

.from-left {
    left:500px {
        transition:0.8s;
    };
}

Because if the transitions really are about a property, well, why not express it as such in the language too?

This is probably not the best way, but just the first thing that came to mind, which I am sure will break all parsers. But in any case, I’m looking forward to the changes of the spec that would a) somehow help out with cascading and b) make the shorthand syntax for multiple properties more approachable. In fact, there is a somewhat related comment when discussing transition properties:

We may ultimately want to support a keypath syntax for this property. A keypath syntax would enable different transitions to be specified for components of a property. For example the blur of a shadow could have a different transition than the color of a shadow.

Whoa. So, we would then have transition rules that apply no longer to an element, nor to a property of an element, but the subproperty of a property of an element? That would, of course, be cool, but I wonder what the markup for that would be like, and if you can somehow cascade that too.

This is literally my first day looking at CSS3 transitions (and maybe the last as well for a while), so if I was incorrect anywhere, please correct me.