Skip to content

[css-values] Differences between calc() handling for <length-percentage> values. #3482

Closed

Description

@emilio

I was doing some work in Gecko and realized various inconsistencies with how we treat calc(). I saw that other browsers have other (different) inconsistencies. I'm fixing some of those where it seems reasonable and we all agree. But I'm having trouble to find what the model is supposed to be.

I'll try to break this down to simpler questions...

Should calc(%) always be treated the same as %

It looks to me like it should, but in Gecko right now this is not always the case. For example, in the containing-block-size quirk, Gecko will only apply it to non-calc percentages, intentionally:

https://searchfox.org/mozilla-central/rev/ecf61f8f3904549f5d65a8a511dbd7ea4fd1a51d/layout/generic/ReflowInput.cpp#2162

<style>
  body { margin: 0 }
  div {
    height: 100%;
    float: left;
    width: 50%;
    background: green;
  }
  div + div {
    height: calc(100%);
    background: orange;
  }
</style>
<div></div>
<div></div>

Should calc(% + 0px) be equivalent to calc(%)?

I intuitively thought it should, but browsers differ here. For example, these two tables look different in blink / webkit:

<!doctype html>
<table border>                                                                                                                                                                                                     
  <tr>                                                                                                                                                                                                             
    <td style="width: calc(50%)">x</td>                                                                                                                                                                            
    <td style="width: 100px">y</td>                                                                                                                                                                                
</table>
<table border>                                                                                                                                                                                                     
  <tr>                                                                                                                                                                                                             
    <td style="width: calc(50% + 0px)">x</td>                                                                                                                                                                            
    <td style="width: 100px">y</td>                                                                                                                                                                                
</table>

I think they should render the same though (though I could be convinced otherwise).

Should calc(<length> + 0%) be the same as calc(<length>)?

I tend to think it should not, since we special-case percentages in quite a few places, and 0% is not the same as 0px everywhere (I'm pretty sure it's not the same in grid track sizing for example). Also intrinsic sizing, and this is a test passing in all browsers:

https://searchfox.org/mozilla-central/rev/ecf61f8f3904549f5d65a8a511dbd7ea4fd1a51d/testing/web-platform/tests/css/css-sizing/intrinsic-percent-non-replaced-001.html#38

I think the simplest model to get something consistent and simple implementation-wise is to keep track only whether percentages were specified, and make % + 0px always the same as %, or alternatively track both whether lengths and percentages were specified (though that's a bit more complex).

/cc @dbaron @Loirooriol @gtalbot

Activity

  1. Loirooriol commented on Jan 4, 2019

    @Loirooriol
    Contributor

    Should calc(%) always be treated the same as %

    https://drafts.csswg.org/css-values-4/#calc-serialize says

    If this simplification process results in only a single value (one <number>, one <dimension>, or one <percentage>), and the value being serialized is a computed value or later, serialize it just as that one value, without the calc() wrapper.

    I think it would be bad if the serialization is the same but the behavior can be different.

    Should calc(<length> + 0%) be the same as calc(0%)?

    In general they seem clearly different, I think you meant calc(<length>) instead of calc(0%).

    And I agree the 0% should not disappear, this seems already specified in https://drafts.csswg.org/css-values-4/#calc-computed-value

    Where percentages are not resolved at computed-value time, they are not resolved in math functions, e.g. calc(100% - 100% + 1em) resolves to calc(1em + 0%), not to 1em. If there are special rules for computing percentages in a value (e.g. the height property), they apply whenever a math function contains percentages.

    Should calc(% + 0px) be equivalent to calc(%)?

    Not that sure about this one. Theoretically I think they may be considered to be different, but in practice I would probably expect e.g. CSS Tables to say they should be equivalent in your example.

  2. Ernedar commented on Jan 4, 2019

    @Ernedar

    Should calc(%) always be treated the same as %

    https://drafts.csswg.org/css-values-4/#calc-serialize says

    If this simplification process results in only a single value (one <number>, one <dimension>, or one <percentage>), and the value being serialized is a computed value or later, serialize it just as that one value, without the calc() wrapper.

    I think it would be bad if the serialization is the same but the behavior can be different.

    It depends how the calc() is threated. In my mind the calc() is threated like mathematical operation similar to (A + B) so for example if calc(A + B) is same as (A + B) so the calc(%) will be same as (%) and therefore is no matter if it is with out without those brackets. The different case is when you are using it to calculate something in real time in depency on some attribute like vw or vh. If it is the real time case, calc(%) will never be same as % because browsers are limited in rounding numbers.

  3. emilio commented on Jan 4, 2019

    @emilio
    CollaboratorAuthor

    Note that browsers do simplify away 0% and 0px in a bunch of cases, though I'd consider the 0% disappearing a bug.

  4. emilio commented on Jan 4, 2019

    @emilio
    CollaboratorAuthor

    Also:

    In general they seem clearly different, I think you meant calc(<length>) instead of calc(0%).

    Yes, I edited the original post :)

  5. tabatkins commented on Jan 4, 2019

    @tabatkins
    Member

    calc(%) vs %

    Yeah, should be the same as much as possible, because calc(%) will serialize to %, as @Loirooriol says.

    calc(% + 0px) vs calc(%)

    Sure. There's no case in which these two should be different. Lengths never have magical behavior, so adding it to a % shouldn't add any complications, and in the rare cases where length+% is different than just resolving the % and adding the two together (bg-position), a 0px length is still a no-op.

    More specifically, the average of calc(% + 1px) and calc(% - 1px) will, in every case I can see, be the same as as calc(%).

    calc(length + 0%) vs calc(length)

    No, these are different. %s can bring magic, as they sometimes resolve to intrinsic values or behave as auto. Same argument as above, but with opposite result: the average of calc(length + 1%) and calc(length - 1%) is not, in some cases, the same as calc(length) .

  6. emilio commented on Jan 5, 2019

    @emilio
    CollaboratorAuthor

    Alright, so you're in agreement with my intuition, that's great :)

    Now we just need to fix implementations then, and maybe add a note to the spec?

  7. fantasai commented on Jan 10, 2019

    @fantasai
    Collaborator

    The percentages of bg-position aren't special, they're relative to the size of the bg positioning area - size of the image. Which maybe looks magic, but it isn't.

  8. fantasai commented on Jan 10, 2019

    @fantasai
    Collaborator

    @emilio Wrt tables, see last paragraph of https://www.w3.org/TR/css-values-3/#calc-computed-value Your expectation is correct, we just let UAs do weird things in tables because tables are weird.

  9. 68 remaining items

  10. added a commit that references this issue on Nov 18, 2021
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