@bkardell proposes a switch()
function
for providing Container-Query-ish functionality inline in CSS.
The switch() function gets a bit complicated, tho, mixing two distinct and complex grammars (comparisons and <any-value>
) in one spot. It also doesn't let you style multiple properties together; you instead have to write multiple switch()es, one per property, and duplicate your tests, even if a property is only affected in one of the conditions.
Here's an alternate syntax proposal I think I like a little better. There is no change to the power of the proposal.
Create a new conditional rule, called @switch
. It is only allowed nested inside a style rule; if put at the top level, it's invalid.
The @switch contains rules; the prelude of each rule is a condition (which can use information evaluated against the element selectede by the outer style rule), the body is a set of properties to apply to the element when the condition matches.
The first example from Brian's proposal is:
.foo {
display: grid;
grid-template-columns: switch(
(available-inline-size > 1024px) 1fr 4fr 1fr;
(available-inline-size > 400px) 2fr 1fr;
(available-inline-size > 100px) 1fr;
default 1fr;
);
}
In my proposed syntax, it would be written as:
.foo {
display: grid;
@switch {
(available-inline-size > 1024px) { grid-template-columns: 1fr 4fr 1fr; }
(available-inline-size > 400px) { grid-template-columns: 2fr 1fr; }
(available-inline-size > 100px), default { grid-template-columns: 1fr; }
}
}
As you can see, it's a little bit more verbose when you're setting a single property in all the cases, but compare it to the case where you want to set different properties in the branches:
Brian's syntax:
.foo {
display: grid;
grid-template-columns: switch(
(available-inline-size > 1024px) 1fr 4fr 1fr;
(available-inline-size > 400px) 2fr 1fr;
(available-inline-size > 100px) 1fr;
default 1fr;
);
gap: switch(
(available-inline-size > 1024px) 1em;
(available-inline-size > 400px) 0;
(available-inline-size > 100px) 0;
default 0;
);
align-content: switch(
(available-inline-size > 1024px) center;
(available-inline-size > 400px) center;
(available-inline-size > 100px) stretch;
default stretch;
);
}
My syntax:
.foo {
display: grid;
grid-gap: 0;
align-content: center;
@switch {
(available-inline-size > 1024px) {
grid-template-columns: 1fr 4fr 1fr;
grid-gap: 1em;
}
(available-inline-size > 400px) {
grid-template-columns: 2fr 1fr;
}
(available-inline-size > 100px),
default {
grid-template-columns: 1fr;
align-content: stretch;
}
}
}
As soon as you get more properties in, the lessened repetition really starts mattering.
I also think the overall structure is a little easier to visually parse - it looks more like a MQ (and will have and/or/not just like MQs do).
Worth noting that with the
switch()
function it can be said that the property computes to theswitch()
, and just resolve the value during layout.With this
@switch
there is some back and forth between the cascade and layout, since we are enabling and disabling declarations depending on layout. So functionally it seems closer to David's proposal.