This is the repository containing the CSS/TAG Houdini Task Force specifications

  • By World Wide Web Consortium
  • Last update: Jan 8, 2023
  • Comments: 17

CSS-TAG Houdini Task Force Specifications

This is the repository containing the CSS/TAG Houdini Task Force specifications.

In addition to this git repository, a Mercurial mirror is maintained at, if for whatever reason you prefer Mercurial.

Specification issues are raised and discussed in GitHub Issues in this repository.

We also maintain the public-houdini mailing list for general-interest topics.

New specifications are generally first incubated in the WICG, in particular:


For normative changes, a corresponding web-platform-tests PR is highly appreciated. Typically, both PRs will be merged at the same time. Note that a test change that contradicts the spec should not be merged before the corresponding spec change. If testing is not practical, please explain why and if appropriate file an issue to follow up later. Add the type:untestable or type:missing-coverage label as appropriate.



  • 1

    [worklets] relationship to JavaScript agent clusters

    For the worklets that support StructuredSerialize and StructuredDeserialize, see also for the details of that, we'll need to define how worklets relate to JavaScript agent clusters. Otherwise it's unclear whether SharedArrayBuffer always fails or always succeeds.

    Maybe as part of or a follow-up.

    cc @bakulf @domenic @lars-t-hansen

  • 2

    [worklets] dynamic import()

    I thought we already had an issue for this somewhere. If worklets cannot have fetch(), I don't think it makes sense for them to have dynamic import(). That would cause the same kind of execution problems.

    cc @domenic @nhiroki @bfgeek

  • 3

    [css-properties-values-api] Interaction with setProperty is unfortunate.

    The reasoning for that is intentional apparently:

    But I think it's still weird that:

    let div = document.createElement("div");"--foo", "bar");

    Behaves differently to:

    let div = document.createElement("div");
    div.setAttribute("style", "--foo: bar");

    Is this behavior up-for-discussion? I think it is really unfortunate.

    cc @andruud @tabatkins

  • 4

    [css-paint-api] Rename paint(name, args) to paint-name(args)

    The way the Paint API currently works is that it gives authors a paint() function, whose first argument is an <ident> for the name of painting operation.

    However, putting the name of painting in the function call has several benefits:

    • It makes the call easier to read, since the paint name is not really an argument, it's conceptually part of the function.
    • It makes web developers feel that they are creating an actual CSS function, instead of merely extending an existing function.
    • It actually reads nicer, since "paint" combines nicely with the name of what is being painted. There is also more prominent visual separation between the paint operation and the arguments, making it easier to read and process.

    Compare (examples from the spec):

    .logo { background-image: paint(company-logo); }
    .chat-bubble { background-image: paint(chat-bubble, blue); }


    .logo { background-image: paint-company-logo(); }
    .chat-bubble { background-image: paint-chat-bubble(blue); }

    Isn't the latter much easier to read? Doesn't it immediately communicate what it's doing?

    Also, as a polyfill author it is much easier to explain to my users that my script adds a new paint-rainbow() function that they use with x, y, z arguments, than to explain that they have to use this generic paint() function, where the first argument is fixed to rainbow and the rest are the actual arguments they provide.

    I recall mentioning this in person to some Houdini folks ages ago, and they agreed, but I never made an issue so I guess it was forgotten.

  • 5

    [css-typed-om] What does lack of range restriction imply about serialization?

    The section on CSSNumericValue says:

    CSSNumericValue objects are not range-restricted. Any valid numeric value can be represented by a CSSNumericValue, and that value will not be clamped, rounded, or rejected when set on a declared StylePropertyMap or inline StylePropertyMap. Instead, clamping and/or rounding will occur during computation of style.

    (It then proceeds to give an example demonstrating this.)

    What this doesn't seem to address is what implications this has for CSS's existing object model APIs that involve serialization. It's long been a principle of these APIs that they always give output that is valid CSS. This means that, for example, getting, modifying it, and setting it back to should change only the thing that was modified. Likewise for getPropertyValue and setProperty, or the that is equivalent to them. However, the rules for these setters require following the rules of CSS parsing and dropping any declarations that are not valid. This means that serializing things that don't round-trip correctly would break anything that depends on this round-tripping.

    It seem like there are a bunch of bad options here (listed in the order that seems best to worst to me at first glance, although I'm sure I'm missing many considerations):

    • serialize CSSUnitValue that are out-of-range as calc() expressions
    • not do the thing quoted above, but instead do rejection of CSSNumericValues when they're set in some cases
    • serialize all CSSUnitValue as calc() expressions
    • break round-tripping as the spec currently does

    I tried to look through the spec to see if one of these options was specified later, but I didn't see anything. If there is something I missed, it would be good to have a pointer to it from this section.

    It's also entirely possible that the WG has discussed this and I've forgotten (or missed it).

  • 6

    [worklets] (bikeshedding time!) import() name is potentially confusing...

    So the import function has been noted as potentially confusing.

    Other names which have been discussed at some point are: loadModule (@adamk) distributeScript (@annevk)

    For additional context the other way to invoke scripts will be via the script tag most likely, e.g.

    <script worklet="paint" src="paint.js"></script>

    Which is the same as


    From originally.

  • 7

    [css-properties-values-api] Allow custom property descriptors with a CSS @-rule

    The incredible flexibility of CSS Variables / Custom Properties introduces limitations compared to regular properties. By default they:

    • cannot be interpolated in animations & transitions
    • disable any parser-based type checking when used as a var()
    • cannot have a default value, fallbacks must be specified each time a var() is used

    The CSS Properties Values API addresses all these limitations, but requires script to run to do so. This will cause async issues (CSS having to be re-parsed after script runs) and is no use at all in cases where scripts are disabled for security reasons (e.g., SVG-as-image).

    While the general argument for using JS APIs for Houdini has been discussed in #86, I think property declarations are a special case. This isn't about declaring functionality that needs to be represented as script functions; it's merely declaring a data object. An @-rule of descriptors and values seems a perfect fit:

    @property --highlight-color {
      syntax: "<color>";
      initial-value: red;
      inherits: true;
    @property --gap-spacing {
      syntax: "<length-percentage>";
      initial-value: 1em;
      inherits: false;

    It would of course be preferable to always have @property rules earlier in the CSS parsing sequence than any declarations using those properties. However, since it is also going to be possible to set property declarations asynchronously with the API, I don't think this would need to be an enforced syntax rule, just a performance recommendation.

    The effects of this declaration would be the same as for a declaration via the API. E.g., If initial-value isn't specified, it would get the "nothing" initial value described in CSS Custom Properties, with the resulting implication for var() function fallbacks.

    The API currently advises throwing an error if the provided initial value doesn't match the provided syntax. For a @property declaration, I would recommended simply dropping the non-conforming initial value declaration. This could allow multiple declarations with standard CSS fallback methods, e.g., for new functions that might not be recognized:

    @property --highlight-color {
      syntax: "<color>";
      initial-value: red;
      initial-value: lighten(maroon);
      inherits: true;
  • 8

    [css-properties-values-api] Should property registration be scoped?

    The fact that property registration is document global makes it impossible to use a custom property privately in a shadow tree. Maybe registration should be scoped somehow, optimally to a style sheet or shadow scope.

  • 9

    [css-typed-om] Will need to handle min()/max()

    I haven't added it to the spec yet, but the CSSWG resolved to add min()/max() to the V&U spec at the Seattle 2017 f2f. This'll need a new class to represent it properly.

  • 10

    Ban data URL worklets

    Although I thought data URL worklets would be fine, per #506 and implementation reality, static imports are supported, which means worklets have some means of networking. In that case it would be better for data URLs to create their own agent cluster (see also, but that would be kind of pointless, especially for audio worklets. So it makes more sense to network error data URL worklets (to me).

    cc @padenot @nhiroki

  • 11

    [css-paint-api] Running author function without proper preparation.

    In short, invoke a paint callback does not follow Web IDL nor HTML specs. The CSS Painting API spec and its algorithms are defined using ECMAScript directly, and it violates Web IDL and HTML specs.

    I cannot list up all the places that are conflicting with Web IDL and/or HTML, so let me show an example.

    In invoke a paint callback, step 5.3. "Let paintInstance be the result of Construct(paintCtor)."; this step invokes an author function |paintCtor| without performing prepare to run script nor prepare to run a callback. This is NOT allowed in Web IDL nor HTML. |paintCtor| will run without the Incumbent realm having been set up, so we cannot tell what would happen if |paintCtor| invoked an Web API that uses the Incumbent realm.

    I originally reported the same issue to Animation Worklet. It seems better to report this to CSS Paint API, too, so I'm now reporting here.

    Ideally, each Web API spec should not be defined with ECMAScript. Web IDL provides all the necessary abstraction and it's easier with Web IDL to make each spec consistent.

  • 12

    Dependency Cycles via Relative Units with unit algebra

    #315 was fixed without considering "unit algebra". CSS Values 4 allows dividing by dimensions, so we may have

    @property --my-font-size {
      syntax: "<number>";
      inherits: false;
      initial-value: 0;
    div {
      --my-font-size: calc(10em / 1px);
      font-size: calc(var(--my-font-size) * 1px);

    That's a dependency cycle! It's not addressed by, since that only handles registered properties with a syntax of <length> or <length-percentage>.

    The example above uses <number>, but other dimensions like <angle> are also affected:

    --my-font-size: calc(10em / 1px * 1deg);
    font-size: calc(var(--my-font-size) / 1deg * 1px);

    CC @tabatkins

  • 13

    [css-animation-worklet-1] Broken references in CSS Animation Worklet API

    While crawling CSS Animation Worklet API, the following links to other specifications were detected as pointing to non-existing anchors:

    • [ ]
    • [ ]
    • [ ]
    • [ ]
    • [ ]
    • [ ]
    • [ ]
    • [ ]
    • [ ]
    • [ ]
    • [ ]
    • [ ]
    • [ ]
    • [ ]
    • [ ]
    • [ ]

    This issue was detected and reported semi-automatically by Strudy based on data collected in webref.

  • 14

    [css-typed-om] "create a sum value" behavior is undefined for CSSMathClamp type

    "create a sum value" behavior is undefined for CSSMathClamp type:


    This section deals with many types but not CSSMathClamp. I couldn't find anywhere the spec text for what the behavior should be for a CSSMathClamp.

  • 15

    should paint() take rather than ?

    I think the paint() function should perhaps take <custom-ident> rather than <ident>, and forbid the CSS-wide keywords, etc. (This is what Blink implements.)

  • 16

    initial value for universal ("*") syntax definition should not allow CSS-wide keywords

    Right now the steps for registering a custom property appear to allow the initial value for registered properties that use the universal syntax definition ("*") to be a CSS-wide keyword (such as inherit, initial, etc.). Since these values are treated specially in custom properties I think they probably shouldn't be allowed in the initial value of a registered property.

    I think it's possibly also allowed in the non-universal case as well, depending on how you interpret "computationally independent".

    I think these rules should throw an error in step 4 if the value given is a CSS-wide keyword. (It's possible they should also reserve default which is disallowed from being a <custom-ident>, but is not a CSS-wide keyword.)

  • 17

    [css-typed-om-1] Handle `` and ``

    4.3.2. Numeric Value Typing:

    Note: As new unit types are added to CSS, they’ll be added to this list of base types, and to the CSS math functions.

    Is there any particular reason for not supporting <decibel> and <semitones>?

    <decibel> seems to be used in the value definition of cue-after and cue-before (CSS Speech).

    <semitones> seems to be used in the value definition of voice-pitch and voice-range (CSS Speech). Both properties are marked as at-risk:

    The following features are at-risk, and may be dropped during the CR period: voice-balance, voice-duration, voice-pitch, voice-range, and voice-stress

    Both <decibel> and <semitones> are defined as <dimension>s:

    The <decibel> type denotes a dimension with a "dB" (decibel unit) unit identifier.

    The syntax of <semitones> allowed values is a dimension with the unit identifier st (semitones).

    They are missing in CSS Values but generally speaking, wouldn't it be better to refer to the dimensions defined in CSS Values, and avoid explicitly listing the supported dimensions?

    To be honest, I'm also creating this issue to ask a question. I would like to know the reason why type entries must be ordered according to the order of the base types:

    The base types are "length", "angle", "time", "frequency", "resolution", "flex", and "percent". The ordering of a type’s entries always matches this base type ordering.

    I'm trying to find a test case that would fail if they were defined in a different order.