Skip to content

[css-color] Inconsistency of inherited value for color #10536

Open

Description

@matthiasclasen

I've recently tried to firm up the css implementation in GTK to deal properly with currentcolor, and found some inconsistencies with the newer additions to the css-color spec.


In a situation like this:

<div> 
  <div>
    <b>What color is this text?</b>
  </div>
</div>
div {
  color: color(srgb 0 0 1);
}

div > div { 
  color: color-mix(in srgb, currentcolor, color(srgb 1 0 0));
}

What is the used value of the color property for the b element?


Trying to find the used value for the color property on the b element
according to the specs:

Since there is no cascaded value, the specified value is found by inheritance,
so the specified value is the computed value of the color property
on the parent element (css-cascade-5).

For finding out what that is, we look at css-color-5 and find that
the computed value for color-mix with currentcolor is the same color-mix
expression. So the computed value of the color property for the inner
div is

color-mix(in srgb, currentcolor, color(srgb 1 0 0)).

And thus, this is the specified value of the color property for the b element.

The computed value for the b element gets determined the same way again:
a color-mix expression with currentcolor computed to itself. So the
computed value of the color property on the b element is again

color-mix(in srgb, currentcolor, color(srgb 1 0 0)).

To find the used value, we need to substitute currentcolor, since we
are dealing with the color property, the value to use for currentcolor
is the inherited value of the color property (css-color-4), i.e. again

color-mix(in srgb, currentcolor, color(srgb 1 0 0)).

Substituting that into the computed value gives me

color-mix(in srgb, color-mix(in srgb, currentcolor, color(srgb 1 0 0)))

which is bad, since we haven't gotten rid of currentcolor this way.

If we bend the interpretation of the color spec to mean that inside the color property, currentcolor
is replaced by the used value of the color property on the parent element, we end up with

color-mix(in srgb, color(srgb 0.5 0 0.5), color(srgb 1 0 0))

which resolves to

color(srgb 0.75 0 0.25)

This is what my GTK code currently produces.


But when I look at browsers, I get

color(srgb 0.5 0 0.5)

which seems to indicate that browsers instead ignore what css-cascade-5 says and always inherit
the used value for the color property.


I think the specs are inconsistent and need to be clarified in this regard.

Activity

  1. svgeesus commented on Jul 15, 2024

    @svgeesus
    Collaborator

    Right, CSS color 4 says:

    In the color property, the used value of currentcolor is the inherited value. In any other property, its used value is the used value of the color property on the same element.

    Note: This means that if the currentcolor value is inherited, it’s inherited as a keyword, not as the value of the color property, so descendants will use their own color property to resolve it.

    You said:

    Substituting that into the computed value gives me

    color-mix(in srgb, color-mix(in srgb, currentcolor, color(srgb 1 0 0)))
    

    which is bad, since we haven't gotten rid of currentcolor this way.

    Yes, that gives you the used value of the color property. Consider

      <div>
        <b>What color is <em>this</em> text?</b>
      </div>
    </div>
    

    and

    em { color: lime}
    

    the used value of the color property is color-mix(in srgb, color-mix(in srgb, currentcolor, color(srgb 1 0 0))) and the actual value will be color-mix(in srgb, color-mix(in srgb, color(srgb 0 0 1), color(srgb 1 0 0))) on the <b> and color-mix(in srgb, color-mix(in srgb, lime, color(srgb 1 0 0))) on the <em>.

    If we bend the interpretation of the color spec to mean that inside the color property, currentcolor is replaced by the used value of the color property on the parent element, we end up with

    color-mix(in srgb, color(srgb 0.5 0 0.5), color(srgb 1 0 0))
    

    That isn't bending, but it does give you the actual value.

    But when I look at browsers, I get

    color(srgb 0.5 0 0.5)
    

    which is why they fail a bunch of WPT tests related to currentColor, at the moment.

  2. velsinki commented on Jul 15, 2024

    @velsinki

    which is why they fail a bunch of WPT tests related to currentColor, at the moment.

    Aren't https://github.com/web-platform-tests/wpt/blob/master/css/css-color/color-mix-currentcolor-003.html and https://github.com/web-platform-tests/wpt/blob/master/css/css-color/color-mix-currentcolor-nested-for-color-property.html essentially about the problem statement in this issue?

    Browsers pass these tests, but they do not apply the color-mix recursively but instead just inherit the used value. The test

    <style>
    body {
        color: green;
    }
    div {
        color: color-mix(in srgb, currentColor 50%, white);
    }
    div > div {
        color: inherit;
    }
    </style>
    <div>
        <div>This text should be pale green</div>
    </div>

    has reference

    <style>
    div {
        color: color-mix(in srgb, green 50%, white);
    }
    </style>
    <div>
        <div>This text should be pale green</div>
    </div>

    According to the strict interpretation, it could be color-mix(in srgb, currentColor 50%, white) → color-mix(in srgb, color-mix(in srgb, green 50%, white) 50%, white) on the inner div as well, but that's not how the test passes.

  3. svgeesus commented on Jul 16, 2024

    @svgeesus
    Collaborator

    Thanks for the report, it seems those tests need to be revised.

  4. velsinki commented on Jul 16, 2024

    @velsinki

    But isn't the solution to those tests more desirable than implicit recursion? It feels like the same reason why for example relative font size does not apply recursively, unless specified with an explicit (e.g. wildcard) match. To me it makes more sense to clarify that within the color property, currentcolor refers to the used (resolved) parent color.

    How would you otherwise avoid this recursion if you don't want it? You might get weird issues like https://gitlab.gnome.org/GNOME/gtk/-/issues/6833 that are hard to solve just using CSS.

  5. svgeesus commented on Mar 25, 2026

    @svgeesus
    Collaborator

    which is why they fail a bunch of WPT tests related to currentColor, at the moment.

    Noting that the mostly-red results in 2024 are now mostly-green, which implies that browsers have now updated to do what the spec says.

    @velsinki Can this be closed, therefore, or are there still inconsistencies between specs and WPT?

  6. velsinki commented on Mar 25, 2026

    @velsinki

    Afaik, the specs haven't been changed, nor have the tests I linked above. In my opinion, the tests make sense, and so do the browsers passing them.

    But for example https://github.com/web-platform-tests/wpt/blob/master/css/css-color/color-mix-currentcolor-nested-for-color-property.html clearly inherits the used (resolved) color, which as Matthias (and you?) mentions, is not consistent with the specs, which says it should inherit the computed value (unresolved) and thus resulting in recursion.

  7. svgeesus commented on Mar 26, 2026

    @svgeesus
    Collaborator

    Afaik, the specs haven't been changed, nor have the tests I linked above. I

    Right. What has changed is the conformance of browsers to the specs.

    But for example https://github.com/web-platform-tests/wpt/blob/master/css/css-color/color-mix-currentcolor-nested-for-color-property.html clearly inherits the used (resolved) color, which as Matthias (and you?) mentions, is not consistent with the specs, which says it should inherit the computed value (unresolved) and thus resulting in recursion.

    Also true, so leaving this open.

  8. added
    spec-test-mismatchIssues about tests that seem to assume things that contradict the spec or are not specified at all
    on Mar 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

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