w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.51k stars 671 forks source link

[css-values] Grammar syntax for defining default values for optional productions #11189

Open weinig opened 1 week ago

weinig commented 1 week ago

As part of an ongoing effort to generate the parsing and serialization of CSS values from the grammars in specs, one of the most prominent missing pieces of information is the prose defined "default values" for optional productions.

To give some concrete examples, lets take a look at the grammar for the blur() function:

blur() = blur( <length>? )

In prose below the grammar is the text "Default value when omitted is 0px."

If instead, that information was available in a machine readable way, parsing and serialization of would be directly implementable.

This would similarly be beneficial for testing.

I don't have strong opinions on the specifics of a syntax extension, so as a strawman I propose ?=[default value here].

For the example above, this might look like:

blur() = blur( <length>?=[0px] )

This won't work for everything, some defaults are quite complicated, but I think it would move things forward.

weinig commented 6 days ago

To make this more concrete, and show some weaknesses, here are some additional examples of where this could be used:

CSS Images 4

https://drafts.csswg.org/css-images-4/#typedef-linear-gradient-syntax

linear-gradient() = linear-gradient(
  [ [ <angle> | to <side-or-corner> ]?=[to bottom] || <color-interpolation-method>?=[oklab] ] ,
  <color-stop-list>
)
<side-or-corner> = [left | right] || [top | bottom]

https://drafts.csswg.org/css-images-4/#radial-gradients Radial gradient is a bit hard to fit in the scheme due to divergent defaults based on whether an ellipse or circle should be used, though I expect there is an expanded form of the grammar that could work).

https://drafts.csswg.org/css-images-4/#typedef-conic-gradient-syntax

conic-gradient() = conic-gradient( [ <conic-gradient-syntax> ] )
<conic-gradient-syntax> =
  [ [ [ from <angle> ]?=[from 0deg] [ at <position> ]?=[at center ] || <color-interpolation-method> ]?=[oklab] ,
  <angular-color-stop-list>)

https://drafts.csswg.org/css-images-4/#stripes

<image-1D> = <stripes()>
<stripes()> = stripes( <color-stripe># )
<color-stripe> = <color> && [ <length-percentage> | <flex> ]?=[1fr]

CSS Shapes

https://drafts.csswg.org/css-shapes-1/#funcdef-basic-shape-inset It might be useful to be able to specify the behavior behavior of {1,4} adhearing to the "margin" rules. Doing so, would require a way for default values to refer to specific elements within production The spec has this prose: "the omitted values default in the same way as the margin shorthand: an omitted second or third value defaults to the first, and an omitted fourth value defaults to the second".

<inset()> = inset(
  <length-percentage>{1,4}
  [ round <'border-radius'> ]?=[round 0px]
)

and example using made up but hopefully understandable synax for how the "margin" rules could be specified would be something like:

<length-percentage>{1,4} =
    [ <length-percentage>[name=a] ]=[a a a a]
  | [ <length-percentage>[name=a] <length-percentage>[name=b] ]=[a b a b]
  | [ <length-percentage>[name=a] <length-percentage>[name=b] <length-percentage>[name=c] ]=[a b c b]
  | [ <length-percentage> <length-percentage> <length-percentage> <length-percentage> ]

https://drafts.csswg.org/css-shapes-1/#funcdef-basic-shape-xywh

<xywh()> = xywh(
  <length-percentage>{2} <length-percentage [0,∞]>{2}
  [ round <'border-radius'> ]?=[round 0px]
)

https://drafts.csswg.org/css-shapes-1/#funcdef-basic-shape-rect

<rect()> = rect(
  [ <length-percentage> | auto ]{4}
  [ round <'border-radius'> ]?=[round 0px]
)

https://drafts.csswg.org/css-shapes-1/#funcdef-basic-shape-circle The spec actually doesn't specify what should happen in <radial-size> is omited, but CSS Images defaults to farthest-corner.

<circle()> = circle(
  <radial-size>?=[farthest-corner]
  [ at <position> ]?=[at center]
)

https://drafts.csswg.org/css-shapes-1/#funcdef-basic-shape-ellipse The spec actually doesn't specify what should happen in <radial-size> is omited, but CSS Images defaults to farthest-corner.

<ellipse()> = ellipse(
  <radial-size>?=[farthest-corner]
  [ at <position> ]=[at center]
)

https://drafts.csswg.org/css-shapes-1/#funcdef-basic-shape-polygon

<polygon()> = polygon(
  <'fill-rule'>?=[nonzero]
  [ round <length> ]?=[round 0px] ,
  [<length-percentage> <length-percentage>]#
)

https://drafts.csswg.org/css-shapes-1/#funcdef-basic-shape-path No default can be used for <'fill-rule'> for path, as the spec says it is context dependent: "Defaults to nonzero if omitted, unless the function is being used in a context such as SVG shapes where the fill-rule property is relevant. In that case an omitted value will use the computed value of the fill-rule property"

<path()> = path(
  <'fill-rule'>? ,
  <string>
)

CSS Filters

Filters give some interesting cases. A lot is covered, but missing is syntax to specify:

https://drafts.fxtf.org/filter-effects/#funcdef-filter-blur

blur() = blur( <length [0,∞]>?=[0px] )

https://drafts.fxtf.org/filter-effects/#funcdef-filter-brightness

brightness() = brightness( [ <number [0,∞]> | <percentage [0,∞]> ]?=[1] )

https://drafts.fxtf.org/filter-effects/#funcdef-filter-contrast

contrast() = contrast( [ <number [0,∞]> | <percentage [0,∞]> ]?=[1] )

https://drafts.fxtf.org/filter-effects/#funcdef-filter-drop-shadow

drop-shadow() = drop-shadow( [ <color>?=[currentcolor] && [<length> <length> <length>?=[0px]  ] )

https://drafts.fxtf.org/filter-effects/#funcdef-filter-grayscale

grayscale() = grayscale( [ <number [0,∞]> | <percentage [0,∞]> ]?=[1] )

https://drafts.fxtf.org/filter-effects/#funcdef-filter-hue-rotate

hue-rotate() = hue-rotate( [ <angle> | <zero> ]?=[0deg] )

https://drafts.fxtf.org/filter-effects/#funcdef-filter-invert

invert() = invert( [ <number [0,∞]> | <percentage [0,∞]> ]?=[1] )

https://drafts.fxtf.org/filter-effects/#funcdef-filter-opacity

opacity() = opacity( [ <number [0,∞]> | <percentage [0,∞]> ]?=[1] )

https://drafts.fxtf.org/filter-effects/#funcdef-filter-saturate

saturate() = saturate( [ <number [0,∞]> | <percentage [0,∞]> ]?=[1] )

https://drafts.fxtf.org/filter-effects/#funcdef-filter-sepia

sepia() = sepia( [ <number [0,∞]> | <percentage [0,∞]> ]?=[1] )