Skip to content

[css-values-4] Should progress() functions clamp to 0-100%? #11825

Closed

Description

@fantasai

A lot of use cases for the progress functions require clamping the value to 0-100%. Some use cases don't... but the driving use cases generally do.

Should progress() clamp to 0-100% by default? It's always possible to get the unclamped result by using calc().

If it doesn't, then authors will need to manually clamp it all the time, which probably gets annoying, especially since you need to repeat the start/end values. clamp(0%, progress(_value_, 0%, 100%), 100%)...

Activity

  1. Loirooriol commented on Mar 5, 2025

    @Loirooriol
    Contributor

    I wouldn't clamp, just like for #6701

    It would seem very weird to me if progress(200px, 0px, 100px) was 1 despite 200px being farther than 100px from 0px.

  2. kizu commented on Mar 7, 2025

    @kizu
    Member

    This is something I thought about, and in the use cases where I tried progress(), I always wanted it to be clamped. And wrapping something with clamp(0, progress(), 1) was a bit cumbersome.

    I wonder if we can make this to be controlled by an optional keyword inside progress()?

    Like progress(clamped, 200px, 0px, 100px) if it is not clamped by default, or something like progress(full, 200px, 0px, 100px) if we decide to clamp by default.

    Even without default clamping, having a keyword for this common case will be better than manually clamping. Personally, I would prefer to optimize for the more common use cases. But that's not a strong preference.

  3. fantasai commented on Mar 7, 2025

    @fantasai
    CollaboratorAuthor

    Maybe progress() and unlimited-progress() ?

  4. Crissov commented on Mar 8, 2025

    @Crissov
    Contributor

    It feels like there was a single word for unlimited progress, advance() perhaps?

  5. jensimmons commented on May 19, 2025

    @jensimmons
    Contributor

    As I started to use progress(), I was quite surprised that it doesn't clamp. I believe it should be clamped! If an author wants to open it up, they can easily set a wider range.

  6. Loirooriol commented on May 20, 2025

    @Loirooriol
    Contributor

    they can easily set a wider range

    What do you mean? Let's say I want to know how far var(--x) is from 100px, compared with 200px. So for --x: 300px I expect 200% since it's twice as far. What wider range should I use?

    It seems to me that the opposite is true: if the result is not clamped and you want it clamped, you can trivially clamp it with clamp(). But if the result is clamped and you don't want it clamped, then progress() is basically useless.

  7. fantasai commented on Jun 11, 2025

    @fantasai
    CollaboratorAuthor

    clamp(0, progress(_value_, 0%, 100%), 1) is not particularly trivial, and it's a bit obnoxious to write. This is fundamentally a convenience notation, so if it's not convenient what's the point...

  8. Loirooriol commented on Jun 11, 2025

    @Loirooriol
    Contributor
    Author wants to clamp If progress() clamps If progress() doesn't clamp
    Yes progress(value, start, end) clamp(0, progress(value, start, end), 1)
    No calc((value - start) / (end - start)) progress(value, start, end)

    Regardless of whether it clamps or not, the other case will be more obnoxious to write.
    Still, adding clamp(0, _, 1) seems easier to me than doing the math manually (which requires writing start twice, and could be a long expression).
    But of course if >90% of the cases want to clamp, it's better to clamp.

    Or we could cover both behaviors with 2 functions, or change the behavior with an optional parameter

  9. tabatkins commented on Jun 11, 2025

    @tabatkins
    Member

    Yeah, progress(clamp <value>, <start>, <end>) seems like the simplest solution of all of these.

  10. bramus commented on Jun 16, 2025

    @bramus
    Contributor

    With this soon shipping in Chrome and also announced as part of Safari 26 maybe we should get a resolution on the clamping behavior?

    I don’t enough experience to decided on whether it should clamp by default or not, but reading the comments here (and drawing parallels to overallProgress) perhaps it should?

    Tab’s suggestion to add a clamp keyword also seems like a viable and easy to achieve route, but OTOH the same can be said for adding an unclamped keyword if the function were to clamp by default.

  11. tabatkins commented on Jun 16, 2025

    @tabatkins
    Member

    Oh yeah, I don't have a strong opinion on which way we default; I just have a weak preference to the keyword clamp over unclamped - it's shorter, and matches the clamp() function (with the same, obvious, behavior). So if there's a strong argument to prefer one behavior over the other by default, we should go with that, but if they're roughly equivalent, I think we should default to unclamped and use the clamp keyword.

  12. css-meeting-bot commented on Jun 18, 2025

    @css-meeting-bot
    Member

    The CSS Working Group just discussed [css-values-4] Should progress() functions clamp to 0-100%?, and agreed to the following:

    • RESOLVED: progress clamps by default between 0 and 1; we'll add unclamped keyword, or other keyword if folks have suggestions
    The full IRC log of that discussion <kbabbitt> bramus: this is about the clamping in the progress function
    <kbabbitt> ... which is about to ship in Chrome
    <kbabbitt> ... and Safari
    <kbabbitt> ... currently progress() does not clamp to 0..100%
    <kbabbitt> ... but reading comments there is a request to have it clamp in some way
    <kbabbitt> ... options are: have it clamp by default, add an extra keyword
    <kizu> q+
    <kbabbitt> ... as part of first argument
    <kbabbitt> .. alternative is inverse of clamp by default
    <kbabbitt> ... would like a resolution before this hits
    <kbabbitt> q+
    <Rossen6> ack kizu
    <kbabbitt> kizu: my opinion is we should clamp by default and have unclamp keyword
    <kbabbitt> ... most cases I've tested want this
    <kbabbitt> ... kind of already a shortcut around some math
    <kbabbitt> ... possible to do the same with math already but this makes it more convenient
    <kbabbitt> ... for most cases clamping will add more convenience
    <ydaniv> +1
    <kbabbitt> ... for cases where you need unclamped we can stiill have a keyword
    <fantasai> +1 to kizu
    <TabAtkins> scribe+
    <TabAtkins> kbabbitt: I was curious - I can imagine the use-case for clamped, can someone give a use-case for unclamped progress?
    <TabAtkins> weinig: I think any use-case mimicing an animation, since they can go beyond the 0-100% bounds
    <TabAtkins> weinig: so if you're doing an overshoot, that can be useful
    <flackr> +1
    <TabAtkins> kbabbitt: for css animation, we don't have that behavior, we have basically clamping with fill-mode
    <TabAtkins> flackr: if you have an easing curve, you can easily go beyond the endpoint with animations
    <TabAtkins> kbabbitt: true
    <iank_> (I'm dropping now - would be appreciated if we can bump https://github.com//issues/3059 to next week if possible)
    <TabAtkins> kbabbitt: in progress(), couldn't you achieve that by encoding your stops to form that same curve?\
    <TabAtkins> kbabbitt: i'm mixing this up with interpolate(), nm
    <Rossen6> ack fantasai
    <kbabbitt> fantasai: I think kizu and kbabbitt covered the things I was going to say
    <TabAtkins> fantasai: i think roman and kevin covered what i want to say
    <kbabbitt> ... it is a convenience notation
    <Rossen6> ack kbabbitt
    <TabAtkins> q+
    <kbabbitt> ... clamping would cover most use cases
    <kbabbitt> ... so that should be default behavior
    <Rossen6> ack TabAtkins
    <kbabbitt> TabAtkins: don't have a strong opinon on clamped or unclamped
    <kbabbitt> ... weak preference for unclamped by default and keyword being clamped
    <kbabbitt> ... based on usability of syntax
    <miriam> q+
    <kbabbitt> ... clamped is a shorter word, not conjugated
    <kbabbitt> ... matches what function is doing in the first place
    <kbabbitt> ... ignoring use cases, would go unclamped by default with clamp keyword
    <kbabbitt> ... but if others feel there are strong use cases to go one way or other, happy to defer
    <kbabbitt> +1 to TabAtkins
    <Rossen6> ack miriam
    <kbabbitt> miriam: agree that clamped is the only use case I've run into
    <TabAtkins> `progress(var(--val) clamp, 1, 10)` simpler than `progress(var(--val) unclamped, 1, 10)`
    <kbabbitt> ... there are use cases for unclamped but clamped seems default use case
    <kbabbitt> ... ok as long as switching is simple
    <fantasai> TabAtkins, that assumes you want them both equally. I think we're saying that's not true.
    <kbabbitt> to clarify, my +1 is to "base it on strength of use cases"
    <TabAtkins> Yes, I was just providing the syntax example directly, since kbabbitt minuted me as saying "clamped". ^_^
    <kbabbitt> bramus: if others are saying clamp by default I think that's the way we should go
    <kbabbitt> fantasai: Proposal is that progress clamps by default between 0 and 1
    <kbabbitt> ... and we'll add unclamped keyword, or other keyword if folks have suggestions
    <kbabbitt> RESOLVED: progress clamps by default between 0 and 1; we'll add unclamped keyword, or other keyword if folks have suggestions
  13. 18 remaining items

  14. kbhomes commented on Jun 11, 2026

    @kbhomes
    Contributor

    Should this be tagged as Needs Edits ? This clamping isn't yet reflected in the specification and is still marked as a pending issue.

    In particular, I think the resolution still needs clarity on what to do if start and end are the same. The specification right now says to return either 0, -inf, or +inf depending on whether value is equal, lesser, or greater. With clamping, what should the returned value be? (If applied directly on the infinities, this would be 0 if <= and 1 if >).

  15. tabatkins commented on Jun 12, 2026

    @tabatkins
    Member

    @kbhomes Thanks for the ping on this; it was indeed missing its Needs Edits, so I'd missed working on it. Spec is updated now.

  16. tabatkins commented on Jun 12, 2026

    @tabatkins
    Member

    (I went with no-clamp as the keyword, as it or something in its vicinity got some reasonable support in this thread.)

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