Skip to content

[css-values-4][Editorial] <condition> type that other specs reference #10457

Open
@LeaVerou

Description

This came up when I went to implement the resolution from #10064 and spec my if() proposal.

Currently, we have several specs using one or more types of conditionals, and in every case, this is defined inline. This means the boolean operators (and, or, not) are also defined inline, which is awkward, error-prone, and easy to forget.

Some examples:

Media Queries 5:

<media-query> = <media-condition>
             | [ not | only ]? <media-type> [ and <media-condition-without-or> ]?
<media-type> = <ident>

<media-condition> = <media-not> | <media-in-parens> [ <media-and>* | <media-or>* ]
<media-condition-without-or> = <media-not> | <media-in-parens> <media-and>*
<media-not> = not <media-in-parens>
<media-and> = and <media-in-parens>
<media-or> = or <media-in-parens>
<media-in-parens> = ( <media-condition> ) | <media-feature> | <general-enclosed>

@supports:

<supports-condition> = not <supports-in-parens>
                     | <supports-in-parens> [ and <supports-in-parens> ]*
                     | <supports-in-parens> [ or <supports-in-parens> ]*
<supports-in-parens> = ( <supports-condition> ) | <supports-feature> | <general-enclosed>
<supports-feature> = <supports-decl>
<supports-decl> = ( <declaration> )

CSS Conditional 4 adds…:

<supports-feature> = <supports-selector-fn> | <supports-decl>
<supports-selector-fn> = selector( <complex-selector> )

CSS Conditional 5 adds…:

<supports-feature> = <supports-selector-fn> | <supports-font-tech-fn>
                    | <supports-font-format-fn> | <supports-decl>
<supports-font-tech-fn> = font-tech( <font-tech> )
<supports-font-format-fn> = font-format( <font-format> )

@container:

<container-condition> = [ <container-name> ]? <container-query>
<container-name> = <custom-ident>
<container-query>     = not <query-in-parens>
                      | <query-in-parens> [ [ and <query-in-parens> ]* | [ or <query-in-parens> ]* ]
<query-in-parens>     = ( <container-query> )
                      | ( <size-feature> )
                      | style( <style-query> )
                      | <general-enclosed>

<style-query>         = not <style-in-parens>
                      | <style-in-parens> [ [ and <style-in-parens> ]* | [ or <style-in-parens> ]* ]
                      | <style-feature>
<style-in-parens>     = ( <style-query> )
                      | ( <style-feature> )
                      | <general-enclosed>

@import:

<import-conditions> = [ supports( [ <supports-condition> | <declaration> ] ) ]?
                     <media-query-list>?

Tab’s @when proposal:

media() = media( [ <mf-plain> | <mf-boolean> | <mf-range> ] )
supports() = supports( <declaration> )

In fact, there is an inline issue right there proposing a lighter form of what I’m arguing for here:

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.

Proposal

I propose we introduce a new <boolean> or <condition> value type that other specs can reference.
It will include both the grammar for the boolean algebra, as well as bare and functional forms for each conditional.
Each conditional type should also include metadata like:

  • Can it change over the course

Not all condition types need to be defined in values, we could extend the <condition> token in other specs, as we often do with value types. E.g. size queries may be a better fit in css-contain, since they are not valid anywhere else.

The prose should explain that specs using <condition> should specify:

  1. Which types of conditions are allowed?
  2. Which types of conditions can be specified bare, i.e. without a function name.

To make this more concrete, this is the state of the current specs with conditionals with this framing:

Host supports() media() size() style()
@container - - - ✅ Bare
@supports ✅ Bare - - -
@media - ✅ Bare - -
@import - ✅ Bare -
if() -
@if / @when -

While this change is editorial, I think it will pave the way for a lot of quick DX wins involving mixing and matching conditions (e.g. supports() in @media.

It could also allow creating JS APIs that handle conditions generically, avoiding the current issue of e.g. having matchMedia() for media queries, but no way to detect when a container query matches or not.

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions