Proposal: @-rule for containing exclusive @media rules

Problem description:

Media queries provide the equivalent of an "if" statement, but not an 
equivalent of "else".  While "else" is generally syntactic sugar (in the 
sense that you can always replace "if (x) {} else {}" with "if (x) {} if 
(not x) {}", it's very useful syntactic sugar, especially in cases that 
involve an if cascade.

Specifically, consider how one would express "Use rule set A if width is 
500px or less, use rule set B if width is more than 500px but no more 
than 1000px, use rule set C if width is more than 1000px".  As far as I 
can tell, this cannot be done, because max-width and min-width describe 
closed ranges, there is no "or", and "not" can only appear at the start 
of a query.  As a result, I believe there is no way to express "500px < 
width <= 1000px" as a media query.

That leaves web developers with two options: either doing hacks to 
account for the case when both A and B are applied or doing things like:

   @media (max-width: 500px) {
     A
   }
   @media (max-width: 1000px) and (min-width: 500.000001px) {
     B
   }
   @media not (max-width: 1000px) {
     C
   }

For this specific case we can ameliorate things a bit by adding "or" or 
allowing "not" in the middle somewhere, but the result will still be a 
bit painful to author.  And should an author have the misfortune to want 
a more complicated set of constraints (e.g. something on width, height 
_and_ aspect ratio), I think the author is in trouble.

Proposed solutions:

With that in mind, I would like to propose that we introduce an 
effective equivalent of C's switch() or Python's if/elif/else, as 
follows:  Define a new @-rule (names welcome; for now let's call it 
@pickone, because I haven't thought of a good name) which can contain 0 
or more @media rules followed by 0 or more rulesets.  This is processed 
by applying only the rulesets within the first @media child whose media 
query matches.  If none of them match, the ruleset children are applied.

Using this construct, the use case I describe above would be handled 
like so:

   @pickone {
     @media (max-width: 500px) {
       A
     }
     @media (max-width: 1000px) {
       B
     }
     C
   }

Additional notes:

1) We could also address this by simply adding a way to do "else" to 
@media, but that would require if/else cascades that are harder to read 
than what I propose, I think.

2) One issue with the above proposal is that degradation in a browser 
that does not support @pickone is not great.  I don't see a great way 
around that, though if @supports could test for support for @-rules at 
least something could be hacked together.  If people have ideas for 
making this better, I'm all ears.

3) This obviously doesn't help other consumers of media queries, like 
@import and <link>.  To address those we'd need to add more options for 
boolean operations to media queries (e.g. "or" and/or allowing "not" on 
individual expressions) and let authors deal with the resulting boolean 
logic hell.  My suggestion for doing @import sanely is to simply allow 
@import inside @media, for what it's worth.  I don't have a good 
suggestion for <link>

Thoughts?

-Boris

Received on Monday, 22 October 2012 00:47:54 UTC