the missing css combinator

on
January 13, 2010

Sometimes a long-lasting, nagging problem can take concrete form in the weirdest of circumstances. Something that's been bothering you for a very long time at a rather subconscious level suddenly leaps forward and calls out for immediate attention. More concretely, this article will be about a css combinator oddly lacking from our list of options, not even mentioned in the latest css3 specs (as far as I know).

the problem

First of all, let's take some time to define the problem. If you're serious about web design and css you've probably learned how to think web components rather than web pages by now. Style a component, style possible variants, use them everywhere and style them according to a changing context. This is a very clean way of working, but effectively not truly supported in css yet. Not even in the most experimental of specs.

<div class="focusBlock"> <header>...</header> <section>...</section> <footer>...</footer> </div>

Consider the html code above. A simple focus block (a somewhat generic name for a block that can be used for whatever content promotion - can be used in main content, contextual column and even navigation column). I've used some html5 elements to make the function of the nested elements a little clearer. The difficulty here is that just about anything can be nested within the section part of our focus block. For all you know (and care), they nest an article with its own header and footer section inside. That's where our styling problems start.

/* focus block ....................... */ .focusBlock>header

The little piece of css above shows the best way to style the focus block as a component. The > combinator makes sure that nested components don't inherit unnecessary styling rules belonging to the focus block. This method can already be used in all browsers (except for IE6). Sadly there's no real IE6 alternative to make it work well, and leaving it as is leads to rather ungraceful degradation. Annoying, but not the core issue right now.

The child combinator (as it is called) is a really helpful tool, but when taking a closer look it doesn't really provide a one on one match for our problem. There are two situations where it will fail horribly. First of all adding wrappers (usually divs) inside the focus block (and around the header, section and footer) will break the css completely. I know these elements are considered a "temporary setback" among the powers that be, but even then extra structural elements (with structural relevance, not added for mere graphical trickery) could mess up the css. Not good.

Even if you think the first reason is not strong enough, there's always a couple of functional tags that could equally break the css. What if you need to add a form or link tag (we can do that now!) around the header/section/footer? It will again break the css you've written before, even though the elements you've added have little relevance to content and style. It's a shame that every time such changes are made we have to go back to the css to fix things.

the solution

What we're missing is a combinator with a functionality that lies between the space combinator and the child combinator. A combinator that expresses that a selector can be anywhere below its parent, but only the first (level) it encounters will receive the css rules. What this combinator should be named or which symbol should be used is not something I'd like to worry about, but his functionality is painfully missing from our css today (and tomorrow). It's the only way to express the style of component in a truly flexible and logical way.

conclusion

I can respect the relative complexity of implementing such a combinator, but I believe it's an important functionality that would finally enable us to translate a design to css the same way we conceive it with our minds. I find it a little strange that such a combinator is still missing, so I assume there were good reasons to neglect such a combinator in the past. That said, I hope this article presents some solid arguments to possibly re-open an older discussion.