Skip to content

[css-values] Computed value of a negative calc unit that doesn't allow negative lengths. #434

Closed

Description

@emilio

In the CSS values spec, section 8.1.4. Range Checking:

However, the used value resulting from an expression must be clamped to the range allowed in the target context.

Note that the used value is expected to be clamped, but not the computed value. Both Blink and Firefox (at least, probably other engines too) clamp the value at computed value time, as can be seen running the following test, where all the properties that don't accept negative lengths (like font-size, padding-xxx, etc.) report a computed value of 0px instead of the expected -1px.

<!doctype html>
<script>
window.onload = function() {
  let style = window.getComputedStyle(document.body);
  for (prop of style) {
    if (prop in document.body.style) {
      document.body.style[prop] = 'calc(-1px)';
      console.log(prop, "reported: ", getComputedStyle(document.body)[prop]);
    }
  }
}
</script>

Activity

  1. emilio commented on Aug 30, 2016

    @emilio
    CollaboratorAuthor
  2. emilio commented on Aug 31, 2016

    @emilio
    CollaboratorAuthor

    For the record, Firefox does follow the spec correctly, but clamps the value in GetComputedStyle. I guess that's more of another kind of issue.

  3. dbaron commented on Aug 31, 2016

    @dbaron
    Member

    For properties where the computed value is a length (i.e., calc()s are computed at computed value time) like font-size, we clamp to nonnegative values at computed value time. For properties where the calc() expression is part of the computed value space (like padding-left) we have clamping at used value time (both in the GetComputedStyle code and in the code that actually uses the value).

    I think the spec is still wrong for properties that accept calc() but where calc() is not part of the computed value space since it can be fully computed by computed value time (e.g., font-size).

  4. reopened this on Aug 31, 2016
  5. emilio commented on Aug 31, 2016

    @emilio
    CollaboratorAuthor

    Yeah, and WebKit (and Blink) also clamp (edit: lengths, of course) at computed value time, see https://github.com/WebKit/webkit/blob/e999a05729f1c284fd6e734b88e81a2b078ed80f/Source/WebCore/css/CSSCalculationValue.cpp#L195

  6. changed the title [-][css-values] Computed value of a negative calc unit in that doesn't allow negative lengths.[/-] [+][css-values] Computed value of a negative calc unit that doesn't allow negative lengths.[/+] on Sep 2, 2016
  7. tabatkins commented on Mar 31, 2017

    @tabatkins
    Member

    Note that getComputedStyle() returns the used value for a number of length-using properties, so that pollutes the data quite a bit here. WebKit/Blink doesn't actually have a separate notion of "computed value" in the engine.

  8. css-meeting-bot commented on May 24, 2017

    @css-meeting-bot
    Member

    The CSS Working Group just discussed CSS Values and Units: clamping calc().

    The full IRC log of that discussion <fantasai> Topic: CSS Values and Units: clamping calc()
    <fantasai> github topic: https://github.com//issues/434
    <myles> fantasai: this question was about when things get clamped, if you have a property which doesn't accept negative lengths, for example, the spec says that the used value is clamped, but the computed value is not clamped, and there is some disagreement about whether that is waht is implemented
    <myles> fantasai: dbaron says that calc() is computed at computed value liek font size
    <fantasai> dbaron's comment:
    <fantasai> For properties where the computed value is a length (i.e., calc()s are computed at computed value time) like font-size, we clamp to nonnegative values at computed value time. For properties where the calc() expression is part of the computed value space (like padding-left) we have clamping at used value time (both in the GetComputedStyle code and in the code that actually uses the value).
    <fantasai> I think the spec is still wrong for properties that accept calc() but where calc() is not part of the computed value space since it can be fully computed by computed value time (e.g., font-size).
    <fantasai> https://github.com//issues/434#issuecomment-243933445
    <myles> Rossen: to further TabAtkins's latest point, some or most of this is referring to getComputedStyle() which returns used values not computed values
    <myles> Rossen: it seems like WebKit and blink don't have a separate notion of computed values, and this is a transient value for them
    <myles> dbaron: there is some value which gets inherited. If you have "25% - 30px" and you say this is the computed value and it gets inherited to something which clamps differently, it should be clamped differently
    <myles> Rossen: but you don't know that 25% gets resolved to something > 25px
    <myles> fantasai: but you do know this for some properties
    <myles> fantasai: for padding-left you don't know this, but font-size, you do know this
    <myles> fantasai: you can resolve this at computed value time, and you need to because the value at font-size needs to be computed to a length in order to resolve em
    <myles> Rossen: font-size is the only property which resolves percentages outside of layout
    <myles> fantasai: dbaron: no
    <myles> Rossen: ....
    <myles> Rossen: ok.
    <myles> fantasai: dbaron, do you have a proposal?
    <myles> dbaron: not off the top of my head
    <myles> dbaron: i could write one
    <myles> fantasai: yes please
    <myles> dbaron: we need a distinction where calc() is resolved at computed value time and where calc() is part of a computed value. these needs separate rules
    <myles> fantasai: ok.
    <myles> fantasai: in the first case, we would do the clamping at computed value time, and the second case, it would be at used value time
    <myles> dbaron: yes
    <myles> Rossen: how is this observable?
    <myles> dbaron: the difference is observable through inheritance. but also, some fo the combinations of ways of specifying it, it doesn't make any sense
    <myles> fantasai: let's resolve
    <myles> Rossen: we need a proposal
    <myles> fantasai: i can write a proposal
    <myles> fantasai: w/ dbaron's review
    <myles> Rossen: let's see the prose before we resolve
    <myles> fantasai: sounds good
  9. tabatkins commented on Jun 9, 2017

    @tabatkins
    Member

    Current text is:

    Parse-time range-checking of values is not performed within ''calc()'',
    and therefore out-of-range values do not cause the declaration to become invalid.
    However, the used value resulting from an expression
    must be clamped to the range allowed in the target context.

    I propose we change this to:

    Parse-time range-checking of value is not performed within ''calc()'',
    and therefore out-of-range values do not cause the declaration to become invalid.
    However, at the point in the value computation process where the ''calc()'' can be resolved to a single term,
    it must be clamped to the ranged allowed in the target context.
    (For example, 'font-size' can resolve ''calc(10% - 1em)'' to a single term at computed-value time
    (to -.9em, as it turns out),
    which will then clamp to ''calc(0)''.
    ''width: calc(10% - 1em)'', on the other hand,
    can't resolve into a single term until used-value time.)

  10. fantasai commented on Jun 21, 2017

    @fantasai
    Collaborator

    Okay, so there are two interpretations of what dbaron said:

    • That clamping happens at each stage (computed and used), if it is possible at that stage.
    • That clamping happens at the stage in which it's guaranteed to be possible.

    For example, font-size can compute all of its values at computed value time (and indeed, must do so in order for ems to be able to compute elsewhere). It would clamp at computed value time; and clamping at used value time is unnecessary.

    width however depends on layout information to resolve percentages, and therefore it cannot clamp values that mix percentages and lengths at computed value time. Therefore two behaviors are possible:

    • width clamps calc() expressions that do not mix lengths and percentages at computed value time, and clamps calc() expressions that do mix them at used value time
    • width only clamps calc() expressions at used value time.

    The latter seems slightly simpler, but since it means that a property only clamps exactly one time, a property that currently only has computed-value units and then later adds used-value units would change behavior in an author-observable way.

    The wording for each of these options would be different, so we need the WG to resolve on which one.

  11. 19 remaining items

  12. fantasai commented on Feb 3, 2018

    @fantasai
    Collaborator

    Ok, I've checked in the following changes:

    However, the used value resulting from an expression must be clamped to the range allowed in the target context. Clamping is performed on computed values to the extent possible, and also on used values if computation was unable to sufficiently simplify the expression to allow range-checking.

    @emilio @tabatkins Can you let me know if that seems adequate?

  13. tabatkins commented on Feb 9, 2018

    @tabatkins
    Member

    👍

  14. emilio commented on Feb 10, 2018

    @emilio
    CollaboratorAuthor

    Looks good to me, thanks! Maybe noting explicitly that clamping should not be done at specified value time is worth it? WebKit / Blink are buggy here wrt numbers / integers IIRC.

    Haven't checked if it's something mentioned in other places of the spec.

  15. fantasai commented on Feb 10, 2018

    @fantasai
    Collaborator

    @emilio OK, added parenthetical about specified values.

    Clamping is performed on computed values to the extent possible, and also on used values if computation was unable to sufficiently simplify the expression to allow range-checking. (Clamping is not performed on specified values.)

  16. fantasai commented on Feb 10, 2018

    @fantasai
    Collaborator

    Closing out per @emilio’s verification over IRC.

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