scoped css

What with rebuilding my blog and all, I ran into an old problem that I feel deserves some renewed attention. Two years ago I wrote a post about a missing css combinator (trying to overcome the strictness of the child combinator), sadly this combinator didn't find its way in any current (tentative) spec. This issue is more relevant than ever, so here is what I found out when asking how the css working group is trying to deal with this problem.

the problem

<section class="focus"> <header>...</header> <div class="main">...</div> <footer>...</footer> </section> section.focus > header section.focus > footer

I believe a quick recap of the issue I described in my previous article is in order, so here goes. The html setup above sets no extra classes on the header/footer elements, so the best way to style them is through the child combinator. This allows us to style only the header and footer of the focus block and not worry about nested content that might contain its own header and footer elements. Long live the child combinator!

The problem is that extra (sometimes unforeseen) wrappers in between section.focus and header/footer elements will completely destroy our carefully constructed css. Javascript might be inserting extra wrappers, a structural change (block level wrapper link or form) will lead to similar results. While the child combinator is extremely useful, in the end it might be too rigid for the needs of the web as we know it. Only in very controlled circumstances can it be used without worrying of breaking large chunk of css.

call to the w3

So I contacted the css working group once again to revisit this problem, in the hope to find a proper solution to counter this very shortcoming in the future. If you want you can read the entire thread you can, but I'll limit myself to the proposed solutions that were raised in the discussion.

:not syntax

section.focus header:not(section.focus article header)

Using the :not syntax we could single out the elements that should not inherit the css properties of the focus header. While this is somewhat helpful, the list of elements that should not inherit css can become quite long and is not always predicable. If you ask me, the :not syntax should be reserved for exceptions rather than a means to exclude 90% of the cases.

scoped css

@scope (scope-selector) { @stop (stop-selector) { (nested-selector) { ... } }

This is way cooler. A scoped css construction like this would allow you to define the edges of your component that would stop your css from spilling over to nested components. Rather than telling css what's outside your component, you are know telling it where your component ends and everything that's outside those edges should be ignored.

In theory this is quite awesome, at the same time I feel a powerful tool like this might be a weapon of self-destruction in the hands of someone not too familiar with css. I can already imagine an obese css file written in unnecessarily scoped rules. It's a tool that should be used with care by someone who fully realizes the consequences, then again, we're getting to a point where hacks and amateurs are struggling harder and harder to survive, so maybe it's not a bad thing to embrace some trickier tools to make our job a bit easier.

conclusion

I love the idea of scoped css, though it's not really clear to me right now if you can define multiple boundaries for one single component. It's not even certain that this is ever going to make it into the spec or even a proposition, so it's probably best not to get too excited yet.

That said, with ie6 slowly disappearing it's time we start to tackle the problems of the next-gen css (it's sad to call child combinators that, but it's still true I'm afraid). Hopefully the near future will give us something that allows us to finally style a component within the limitations of its own boundaries.