You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[css-values-4] Should progress() functions clamp to 0-100%? #11825
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%)...
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.
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.
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.
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...
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
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.
Oh yeah, I don't have a strong opinion on which way we default; I just have a weak preference to the keywordclamp 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.
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
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 >).
Activity
Loirooriol commentedon Mar 5, 2025
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.kizu commentedon Mar 7, 2025
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 withclamp(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 likeprogress(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.
fantasai commentedon Mar 7, 2025
Maybe
progress()andunlimited-progress()?Crissov commentedon Mar 8, 2025
It feels like there was a single word for unlimited progress,
advance()perhaps?jensimmons commentedon May 19, 2025
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.Loirooriol commentedon May 20, 2025
What do you mean? Let's say I want to know how far
var(--x)is from 100px, compared with 200px. So for--x: 300pxI 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, thenprogress()is basically useless.fantasai commentedon Jun 11, 2025
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...Loirooriol commentedon Jun 11, 2025
progress()clampsprogress()doesn't clampprogress(value, start, end)clamp(0, progress(value, start, end), 1)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 writingstarttwice, 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
tabatkins commentedon Jun 11, 2025
Yeah,
progress(clamp <value>, <start>, <end>)seems like the simplest solution of all of these.bramus commentedon Jun 16, 2025
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
clampkeyword also seems like a viable and easy to achieve route, but OTOH the same can be said for adding anunclampedkeyword if the function were to clamp by default.tabatkins commentedon Jun 16, 2025
Oh yeah, I don't have a strong opinion on which way we default; I just have a weak preference to the keyword
clampoverunclamped- it's shorter, and matches theclamp()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 theclampkeyword.css-meeting-bot commentedon Jun 18, 2025
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 suggestionsThe 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
18 remaining items
Bug 1973054 [wpt PR 53275] - Clamp the result of the CSS progress() f…
Bug 1973054 [wpt PR 53275] - Clamp the result of the CSS progress() f…
Bug 1973054 [wpt PR 53275] - Clamp the result of the CSS progress() f…
Bug 1973264 [wpt PR 53291] - Fixes tests of CSS Values 5 progress() t…
Bug 1973264 [wpt PR 53291] - Fixes tests of CSS Values 5 progress() t…
Bug 1973264 [wpt PR 53291] - Fixes tests of CSS Values 5 progress() t…
Bug 1973264 [wpt PR 53291] - Fixes tests of CSS Values 5 progress() t…
Bug 1973264 [wpt PR 53291] - Fixes tests of CSS Values 5 progress() t…
[M138] Clamp the result of the CSS progress() function
kbhomes commentedon Jun 11, 2026
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
startandendare the same. The specification right now says to return either 0, -inf, or +inf depending on whethervalueis 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 >).[css-values-5] Add no-clamp keyword to progress(). #11825
tabatkins commentedon Jun 12, 2026
@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.
tabatkins commentedon Jun 12, 2026
(I went with
no-clampas the keyword, as it or something in its vicinity got some reasonable support in this thread.)