1. Introduction
This is currently an early draft of the things that are new in level 5. The features in Level 3 and Level 4 are still defined in [css-conditional-3] and [css-conditional-4] and have not yet been copied here.
CSS Conditional Level 5 extends the @supports rule and supports query syntax to allow testing for supported font technologies.
It also adds an @when rule, which generalizes the concept of a conditional rule. Anything that can be expressed in an existing conditional rule can be expressed in @when by wrappng it 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.
It also adds @else rules, which immediately follow other conditional rules and automatically qualify their conditions as the inverse of the immediately preceding rule’s conditions, such that only the first matching rule in a conditional rule chain is applied.
2. Extensions to the @supports rule
This level of the specification extends the <supports-feature> syntax as follows:
<supports-feature> = <supports-selector-fn> | <supports-font-tech-fn> | <supports-font-format-fn> | <supports-decl> <supports-font-tech-fn> = font-tech( <font-tech> ) <font-tech> = [ features-opentype | features-aat | features-graphite | color-colrv0 | color-colrv1 | color-svg | color-sbix | color-cbdt | variations | palettes | incremental ] <supports-font-format-fn> = font-format( <font-format> ) <font-format = [ collection | embedded-opentype | opentype | svg | truetype | woff | woff2 ]
<font-format> and <font-tech> should be imported from css-fonts-4, not defined here.
- <supports-font-tech-fn>
-
The result is true if the UA supports the font tech provided as an argument to the function.
Note: The allowed values for the font-tech() function are the same as those for the tech() function in the '@font-face' src descriptor.
- <supports-font-format-fn>
-
The result is true if the UA supports the font format provided as an argument to the function.
Note: The allowed values for the font-format() function are the same as those for the format() function in the '@font-face' src descriptor.
2.1. Extensions to the definition of support
A CSS processor is considered to support a font tech when it is capable of utilising the specified CSS Fonts 4 § 11.1 Font tech in layout and rendering.
A CSS processor is considered to support a font format when it is capable of utilising the specified CSS Fonts 4 § 11.2 Font formats in layout and rendering.
3. Generalized Conditional Rules: the @when rule
The @when at-rule is a conditional group rule that generalizes the individual conditional group rules such as @media and @supports. It is defined as:
@when <boolean-condition>{ <stylesheet>}
Where <boolean-condition> is a boolean algebra a la Media Queries 4 § 3 Syntax, but with media() and supports() functions as leaves.
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.
The media() and supports() functions are defined as:
media () =media ( [ <mf-plain> | <mf-boolean> | <mf-range>] ) supports () =supports ( <declaration>)
A media() or supports() function is associated the boolean result that its contained condition is associated with.
4. Chained Conditionals: the @else rule
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 its contained rules based solely on its 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 which is then left unstyled.
The @else rule is a conditional group rule used to form conditional rule chains, which associate multiple conditional rules and guarantee that only the first one that matches will evaluate its condition as true. It is defined as:
@else <boolean-condition>?{ <stylesheet>}
@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.
Within a conditional rule chain, the conditions of each conditional group rule are evaluated in order. If one of them is true, the conditions of all following conditional group rules in the chain evaluate to false, regardless of their stated condition.
An @else rule that is not part of a conditional rule chain is invalid and must be ignored.
@when media ( width >=400 px ) andmedia ( pointer: fine) andsupports ( display: flex) { /* A */ } @else supports ( caret-color: pink) andsupports ( background:double-rainbow ()) { /* B */ } @else { /* C */ }
Exactly one of the preceding rules will be chosen, even though the second rule doesn’t exclude large widths, fine points, or flexbox support, and the last rule doesn’t specify anything at all.
To achieve the same result without conditional rule chains, you’d need to write:
@media ( width >=400 px ) 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 >=400 px ) 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 hard to read, requires significant duplication of both conditions and contents, and is very difficult to write correctly. If the conditions got any more complicated (which is not unusual in real-world content), the example would get significantly worse.
The fallback has no test condition, so will always be chosen unless one of the earlier conditions succeeds.
@when font-tech ( color-COLRv1) andfont-tech ( variations) { @font-face { font-family : icons; src : url ( icons-gradient-var.woff2 ); } } @else font-tech ( color-SVG) { @font-face { font-family : icons; src : url ( icons-gradient.woff2 ); } } @else font-tech ( color-COLRv0) { @font-face { font-family : icons; src : url ( icons-flat.woff2 ); } } @else { @font-face { font-family : icons; src : url ( icons-fallback.woff2 ); } }
Notice that in this example, the variable color font is only downloaded if COLRv1 is supported and font variations are also supported.
Notice too that only one of the available options will be downloaded; this would not be the case without @when and @else, as the next example shows.
The fallback might still be used for some characters; for example, if the color font supports only Latin, while the fallback supports Latin and Greek.
@font-face { font-family : icons; src : url ( icons-fallback.woff2 ); @supports font-tech ( color-COLRv1) { @font-face { font-family : icons; src : url ( icons-gradient-var.woff2 ); } }
Security Considerations
No security issues have been raised against this document
Privacy Considerations
The font-tech() and font-format() functions may provide information about the user’s software such as its version and whether it is running with non-default settings that enable or disable certain features.
This information can also be determined through other APIs. However, the features in this specification are one of the ways this information is exposed on the Web.
This information can also, in aggregate, be used to improve the accuracy of fingerprinting of the user.
Acknowledgments
The @when and @else rules are based on a proposal by Tab Atkins.
Changes
Additions since Level 4
- Added @when and @else.
- Extended supports queries to express font capabilities via font-tech() and font-format().