A proposal to extend the concept of CSS conditional rules to arbitrary when/else chains, and supporing this, a proposal to unify the disparate conditional rules into a single grammar.
CSS is a language for describing the rendering of structured documents
(such as HTML and XML)
on screen, on paper, in speech, etc.
Status of this document
1. Introduction
Writing complex media queries or supports queries is difficult,
particularly when you want to do Thing A in one circumstance,
Thing B in another circumstance,
and Thing C otherwise.
This requires carefully crafting your conditional rules to exclude anything matching the other rules,
while also making sure you’re not accidentally over-excluding things and leaving some situations unmatched.
This spec proposes two things to fix this problem.
First, it proposes an @when rule,
which generalizes the concept of a conditional rule.
Anything you can express in an existing conditional rule
can be expressed in @when,
it just has to be wrapped in an appropriate function
to declare what kind of condition it is.
This allow authors to easily combine multiple types of queries,
such as media queries and supports queries,
in a single boolean expression.
Without this,
authors must rely on nesting separate conditional rules,
which is harder to read and write,
presupposes the conditions are to be conjoined with the "and" boolean relation
(with no easy way to indicate anything else),
and restricts their utility in the proposed conditional rule chains.
Second, it proposes the introduction of @else rules,
which follow conditional rules
and automatically qualify their conditions as you’d expect,
such that at most one rule in an conditional rule chain is chosen as active.
Define "boolean algebra, with X as leaves" in a generic way in Conditional,
so all the conditional rules can reference it directly,
rather than having to redefine boolean algebra on their own.
Usually, conditional group rules are independent;
each one has a separate condition,
evaluated without direct reference to any other rule,
and decides whether or not to apply their contained rules
based solely on their condition.
This is fine for simple conditions,
but makes it difficult to write a collection of conditionals that are meant to be mutually exclusive;
authors have to very carefully craft their conditions to not activate when the other rules are meant to,
and make sure the collection of conditionals don’t accidentally all exclude some situation.
The @else rule is a conditional group rule used to form conditional rule chains,
which allow multiple conditional rules to be provided
and guarantee that at most one of them will evaluate their condition as true.
It is defined as:
@else is interpreted identically to @when.
If its <boolean-condition> is omitted,
it’s treated as having a condition that’s always true.
A conditional rule chain is a series of consecutive conditional group rules,
starting with a conditional group rule other than @else,
followed by zero or more @else rules.
There cannot be anything between the successive conditional group rules other than whitespace and/or comments;
any other token "breaks" the chain.
Should we require that only the last @else in a chain can have an omitted condition?
It’s not uncommon for me, when debugging code,
to short-circuit an if-else chain by setting one of them to "true";
I presume that would be similarly useful in CSS?
It’s still pretty easy to see you’ve done something wrong if you omit the condition accidentally.
For example, here’s a (somewhat silly) conditional chain:
@whenmedia(width >= 400px) and media(pointer: fine) and supports(display: flex) {/* A */}@elsesupports(caret-color: pink) and supports(background: double-rainbow()) {/* B */}@else {
/* C */}
Exactly one of the preceding rules will be chosen,
even tho the second rule
doesn’t exclude large widths, fine points, or flexbox support,
and the last rule
doesn’t specify anything at all.
@media(width >= 400px) and (pointer: fine) {@supports(display: flex) {
/* A */
}
@supports not (display: flex) {
@supports (caret-color: pink) and (background: double-rainbow()) {
/* B */
}
@supports not ((caret-color: pink) and (background: double-rainbow())) {
/* C */
}
}
}
@media not ((width >= 400px) and (pointer: fine)) {
@supports (caret-color: pink) and (background: double-rainbow()) {
/* B */
}
@supports not ((caret-color: pink) and (background: double-rainbow())) {
/* C */
}
}
This is simultaneously impossible to read,
requires significant duplication of both conditions and contents,
and is very difficult to write correctly
(I wrote it wrong twice while producing this example).
If the conditions got any more complicated
(which is not unusual in real-world content),
the example would get significantly worse.
Conformance
Document conventions
Conformance requirements are expressed with a combination of
descriptive assertions and RFC 2119 terminology. The key words “MUST”,
“MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”,
“RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this
document are to be interpreted as described in RFC 2119.
However, for readability, these words do not appear in all uppercase
letters in this specification.
All of the text of this specification is normative except sections
explicitly marked as non-normative, examples, and notes. [RFC2119]
Examples in this specification are introduced with the words “for example”
or are set apart from the normative text with class="example",
like this:
This is an example of an informative example.
Informative notes begin with the word “Note” and are set apart from the
normative text with class="note", like this:
Note, this is an informative note.
Advisements are normative sections styled to evoke special attention and are
set apart from other normative text with <strong class="advisement">, like
this: UAs MUST provide an accessible alternative.
Conformance classes
Conformance to this specification
is defined for three conformance classes:
A style sheet is conformant to this specification
if all of its statements that use syntax defined in this module are valid
according to the generic CSS grammar and the individual grammars of each
feature defined in this module.
A renderer is conformant to this specification
if, in addition to interpreting the style sheet as defined by the
appropriate specifications, it supports all the features defined
by this specification by parsing them correctly
and rendering the document accordingly. However, the inability of a
UA to correctly render a document due to limitations of the device
does not make the UA non-conformant. (For example, a UA is not
required to render color on a monochrome monitor.)
An authoring tool is conformant to this specification
if it writes style sheets that are syntactically correct according to the
generic CSS grammar and the individual grammars of each feature in
this module, and meet all other conformance requirements of style sheets
as described in this module.
Requirements for Responsible Implementation of CSS
The following sections define several conformance requirements
for implementing CSS responsibly,
in a way that promotes interoperability in the present and future.
Partial Implementations
So that authors can exploit the forward-compatible parsing rules to assign fallback values, CSS renderers must treat as invalid
(and ignore as appropriate)
any at-rules, properties, property values, keywords, and other syntactic constructs
for which they have no usable level of support.
In particular, user agents must not selectively ignore
unsupported property values and honor supported values in a single multi-value property declaration:
if any value is considered invalid (as unsupported values must be),
CSS requires that the entire declaration be ignored.
Implementations of Unstable and Proprietary Features
Once a specification reaches the Candidate Recommendation stage,
implementers should release an unprefixed implementation
of any CR-level feature they can demonstrate
to be correctly implemented according to spec,
and should avoid exposing a prefixed variant of that feature.
To establish and maintain the interoperability of CSS across
implementations, the CSS Working Group requests that non-experimental
CSS renderers submit an implementation report (and, if necessary, the
testcases used for that implementation report) to the W3C before
releasing an unprefixed implementation of any CSS features. Testcases
submitted to W3C are subject to review and correction by the CSS
Working Group.
Define "boolean algebra, with X as leaves" in a generic way in Conditional,
so all the conditional rules can reference it directly,
rather than having to redefine boolean algebra on their own. ↵
Should we require that only the last @else in a chain can have an omitted condition?
It’s not uncommon for me, when debugging code,
to short-circuit an if-else chain by setting one of them to "true";
I presume that would be similarly useful in CSS?
It’s still pretty easy to see you’ve done something wrong if you omit the condition accidentally. ↵