Proposal for grouping similar descendant selectors

Hello,

I have searched the web and list archives, but haven't found
anything quite similar to what I have in mind.


== The problem ==

In a typical CSS file of the wild you see a common pattern -
groups of descendant selectors sharing the same ancestor
elements:

#header { border: 1px solid black }
#header h1 { color:green }
#header p { font-size: smaller }

#nav ul li { list-style-type: none }
#nav ul a { text-decoration: none }
#nav ul a:hover { background: red; color: white }

This is a useful pattern. You can devide your site into
sections and by prefixing the style rules for each section
with the section name, you will ensure, that styles meant for
one section don't conflict with styles meant for another
section. (At least when the sections themselves don't overlap
in HTML.)

But this pattern does not follow the DRY principle - you have
to repeat the section names all over the code. More code means
more ways to make mistakes (when you type #header 10 times in
a row, there's greater chance of typos than when writing it
just once). Duplicated code means more work when maintaining
(you can't just rename #header - you will have to rename it
everywhere on your stylesheets.)


== Proposed solution ==

I would like to propose an at-rule to group declarations with
similar descendant selectors. The syntax could be something
like that:

@context <selector> {
     <any-css-rule>
     <any-css-rule>
     ...
}

For example the code at the beginning of this e-mail could be
rewritten as follows:

@context #header {
     { border: 1px solid black }
     h1 { color:green }
     p { font-size: smaller }
}

@context #nav ul {
     li { list-style-type: none }
     a { text-decoration: none }
     a:hover { background: red; color: white }
}

Note: the block at the beginning of @context block would be
applied to context element itself. This syntax might seem
weird, but I chose it because this way you can just use
a simple substitution model to understand how @context works:
you just have to substitute the selector at the beginning of
@context block to the beginning of each rule inside that block.

             /-------\
             |       |
             |       V
@context #header { ... { border: 1px solid black }
                    ... h1 { color: green }
                    ... p { font-size: smaller }
}


=== Nesting ===

You should also be able to nest @context-rules. For example:

@context #content {
     h2 { color: red }
     p { font-size: medium }
     blockquote { margin-left: 5em; }

     @context .comment {
         h3 { color: green }
         p { font-size: smaller }
         blockquote { margin-left: 2.5em; }
     }
}

The last rule would be equivalent of:

#content .comment blockquote { margin-left: 2.5em; }


=== Importing ===

This already reduces the code duplication a lot. But you
would gain even more power if you allow @import inside
@context.

Say, you have #content and #sidebar, and you want them to
be styled similarly, except the sidebar text should be smaller.
Simple, just write one genereic stylesheet and link to it
 from both sections:

@context #content {
     @import url(article.css);
}
@context #sidebar {
     @import url(article.css);
     { font-size: smaller }
}

You could even link CSS file from another site and apply
it only to one section of your site, without worrying about any
conflicts.

This would greatly facilitate code reuse. For example I could
write a script-component for a web-page and just include
simple stylesheet with selectors like this:

h1, p, ul, li:first-child, a:visited, ...

And then the user of this script could limit the scope of
my stylesheet to whatever containing element he chooses:

@context #content .calendar { @import "cal.css" }



Sure, there have to be some tremendous drawbacks in my proposal.
Otherwise someone would have already suggested it.
So, what do you think?

--
Rene Saarsoo
http://triin.net

Received on Thursday, 20 September 2007 13:41:28 UTC