Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Variant syntax for switch() function from @bkardell

@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).

@Loirooriol

This comment has been minimized.

Copy link

@Loirooriol Loirooriol commented May 9, 2020

Worth noting that with the switch() function it can be said that the property computes to the switch(), 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment