CSS progress() Function
The CSS progress() function calculates where a value falls within a specified range and returns a normalized number between 0 and 1.
It can be used to convert lengths, percentages, and other compatible numeric values into a relative position within a range. This makes it useful for responsive calculations, proportional styling, and values that change according to a defined minimum and maximum.
Syntax
progress(value, start, end)
The function requires three comma-separated arguments: the value to evaluate, the beginning of the range, and the end of the range.
For example:
progress(50, 0, 100)
progress(25, 0, 100)
progress(75px, 0px, 100px)
progress(1.5, 1, 2)
The first expression returns 0.5, representing the midpoint between 0 and 100.
The function returns a unitless number that can be used in compatible CSS properties and mathematical expressions.
For example:
.box {
opacity: progress(50, 0, 100);
}
The calculated opacity is 0.5.
Parameters
The progress() function accepts three required parameters.
| Parameter | Description |
|---|---|
value |
The value whose position within the range is calculated. |
start |
The beginning of the range, corresponding to a normalized result of 0. |
end |
The end of the range, corresponding to a normalized result of 1. |
All three arguments must have compatible numeric types.
For example:
progress(50px, 0px, 100px)
This is valid because all three values are lengths.
The following is invalid because it mixes incompatible numeric types:
progress(50px, 0, 100)
Use matching units or otherwise compatible CSS numeric expressions for the arguments.
How It Works
The progress() function measures the relative position of a value between two endpoints.
For a normal increasing range, the underlying calculation is:
(value - start) / (end - start)
For example:
progress(75, 0, 100)
The calculation is:
(75 - 0) / (100 - 0) = 0.75
The result indicates that the value is 75% of the way through the range.
Another example:
progress(30, 20, 60)
The calculation is:
(30 - 20) / (60 - 20) = 0.25
The result is 0.25, meaning the value is one-quarter of the way from 20 to 60.
Unlike a percentage value, the returned result is a unitless number.
Range Values
The starting and ending values determine the range used for normalization.
| Expression | Result | Position |
|---|---|---|
progress(0, 0, 100) | 0 | Beginning |
progress(25, 0, 100) | 0.25 | One-quarter |
progress(50, 0, 100) | 0.5 | Midpoint |
progress(75, 0, 100) | 0.75 | Three-quarters |
progress(100, 0, 100) | 1 | End |
The range does not have to begin at zero.
For example:
progress(150, 100, 200)
This returns 0.5 because 150 is halfway between 100 and 200.
The endpoints can also define a decreasing range:
progress(75, 100, 0)
This returns 0.25 because the value has moved one-quarter of the way from 100 toward 0.
Clamping Values
The progress() function clamps its normalized result to the range from 0 to 1.
Values before the starting point produce 0, while values beyond the ending point produce 1.
For example:
progress(-20, 0, 100)
progress(50, 0, 100)
progress(150, 0, 100)
The results are:
| Expression | Result |
|---|---|
progress(-20, 0, 100) | 0 |
progress(50, 0, 100) | 0.5 |
progress(150, 0, 100) | 1 |
This behavior is useful when a calculated value should remain within a predictable normalized range.
For example:
.element {
opacity: progress(var(--value), 0, 100);
}
The calculated result stays between 0 and 1 for finite values and distinct range endpoints.
Using Length Values
The progress() function can normalize compatible CSS length values.
For example:
progress(150px, 100px, 300px)
This returns 0.25 because 150px is one-quarter of the way from 100px to 300px.
Length values can also be supplied through CSS calculations:
.box {
opacity: progress(calc(100px + 50px), 100px, 300px);
}
The result is 0.25.
All three arguments are evaluated as compatible lengths before the function calculates their relative position.
The final result is unitless, even when the input arguments contain length units.
Using Custom Properties
CSS custom properties can provide the value and range endpoints used by progress().
For example:
.element {
--current: 60;
--minimum: 0;
--maximum: 100;
opacity: progress(var(--current), var(--minimum), var(--maximum));
}
The function returns 0.6.
Changing --current changes the calculated result without modifying the expression.
For example:
.element-low {
--current: 20;
}
.element-medium {
--current: 50;
}
.element-high {
--current: 80;
}
These values produce normalized results of 0.2, 0.5, and 0.8 when the range remains 0 to 100.
Custom properties make it easier to reuse the same calculation with different inputs.
Responsive Design
The progress() function can calculate a normalized value from a changing CSS measurement.
For example:
.responsive-box {
opacity: progress(50vw, 200px, 800px);
}
The function evaluates the viewport-relative length and determines where it falls between 200px and 800px.
The result changes as the viewport width changes.
Another example uses the normalized result as part of a scale calculation:
.responsive-box {
transform: scale(calc(0.8 + 0.4 * progress(50vw, 200px, 800px)));
}
The calculated scale ranges from 0.8 to 1.2.
At the beginning of the range, progress() returns 0, producing a scale of 0.8.
At the end of the range, it returns 1, producing a scale of 1.2.
This approach allows a numerical style value to respond proportionally to a changing measurement.
progress() vs. clamp()
The progress() and clamp() functions both work with ranges, but they return different kinds of results.
| Feature | progress() | clamp() |
|---|---|---|
| Purpose | Normalizes a value within a range | Restricts a value between minimum and maximum limits |
| Result | Unitless number from 0 to 1 | Value in the original numeric type |
| Arguments | Value, start, end | Minimum, preferred, maximum |
| Typical use | Proportional calculations | Constrained sizing and values |
For example:
progress(50px, 0px, 100px)
This returns 0.5.
By comparison:
clamp(0px, 50px, 100px)
This returns 50px.
Use progress() when a normalized fraction is needed, and clamp() when a value must remain between two limits.
Example
This example uses progress() to calculate the opacity of three colored boxes from numerical values.
HTML:
<div class="progress-demo">
<div class="progress-demo-item">
<div class="progress-demo-box progress-low"></div>
<p>25% Progress</p>
</div>
<div class="progress-demo-item">
<div class="progress-demo-box progress-medium"></div>
<p>50% Progress</p>
</div>
<div class="progress-demo-item">
<div class="progress-demo-box progress-high"></div>
<p>75% Progress</p>
</div>
</div>
CSS:
.progress-demo {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 20px;
}
.progress-demo-item {
text-align: center;
}
.progress-demo-box {
width: 130px;
height: 100px;
background-color: #0066cc;
}
.progress-demo-item p {
margin: 10px 0 0;
}
.progress-low {
opacity: 0.25;
opacity: progress(25, 0, 100);
}
.progress-medium {
opacity: 0.5;
opacity: progress(50, 0, 100);
}
.progress-high {
opacity: 0.75;
opacity: progress(75, 0, 100);
}
25% Progress
50% Progress
75% Progress
The first box has an opacity of 0.25, the second has an opacity of 0.5, and the third has an opacity of 0.75.
Each value is calculated relative to the range from 0 to 100.
The preceding fixed opacity declarations provide fallbacks for browsers that do not support progress().
Responsive Example
This example uses progress() to calculate a scale factor from the viewport width.
HTML:
<div class="progress-responsive-demo">
<div class="progress-responsive-box">Responsive</div>
</div>
CSS:
.progress-responsive-demo {
display: flex;
align-items: center;
justify-content: center;
min-height: 220px;
padding: 30px;
overflow: hidden;
background-color: #f1f3f5;
}
.progress-responsive-box {
display: flex;
align-items: center;
justify-content: center;
width: 150px;
height: 100px;
background-color: #0066cc;
color: #ffffff;
font-weight: bold;
transform: scale(1);
transform: scale(calc(0.8 + 0.4 * progress(50vw, 200px, 800px)));
}
The box scales according to the normalized value calculated from half the viewport width.
As the viewport width changes, the calculated scale changes between 0.8 and 1.2.
In browsers without progress() support, the box retains its fallback scale of 1.
Common Uses
The progress() function is useful whenever CSS needs a normalized numerical value.
| Use | Description |
|---|---|
| Responsive styling | Normalize changing dimensions or viewport measurements. |
| Opacity calculations | Convert numerical values into opacity levels. |
| Scaling effects | Calculate proportional transform scale factors. |
| Custom properties | Generate normalized results from configurable values. |
| Range calculations | Determine a value's relative position between two endpoints. |
| Mathematical expressions | Combine normalized values with other CSS math functions. |
For example:
.fade {
opacity: progress(40, 0, 100);
}
.scale {
transform: scale(calc(0.5 + progress(75, 0, 100)));
}
.responsive {
opacity: progress(50vw, 200px, 800px);
}
Each example uses the normalized result in a different CSS calculation.
The function does not represent the state of an HTML <progress> element. It is a mathematical function that calculates a relative position within a range.
Limitations
The progress() function has several important rules and limitations.
- It requires exactly three arguments: value, start, and end.
- The arguments must have compatible CSS numeric types.
- The function returns a unitless number.
- For finite values with distinct endpoints, the result is clamped between 0 and 1.
- Equal starting and ending values require special handling and should be avoided for predictable calculations.
- The result must be valid for the CSS property receiving it.
- It does not create a visible progress bar by itself.
- It does not automatically read values from HTML form controls.
- Browser support is limited compared with established CSS mathematical functions.
- Fallback declarations are recommended for important styling.
For example, this is valid:
opacity: progress(50, 0, 100);
The following is invalid because an argument is missing:
opacity: progress(50, 100);
The following is invalid because the arguments use incompatible numeric types:
opacity: progress(50px, 0, 100);
For predictable results, use compatible values and distinct range endpoints.
Browser Support
The CSS progress() function has Limited availability and is not Baseline across all major browsers.
It is a newer CSS mathematical function, and support may vary between browser versions.
For example:
.box {
opacity: 0.5;
opacity: progress(50, 0, 100);
}
Browsers that support progress() calculate the normalized value. Browsers that do not support the function retain the preceding valid declaration.
Feature detection can also be used:
@supports (opacity: progress(50, 0, 100)) {
.box {
opacity: progress(50, 0, 100);
}
}
The @supports rule checks whether the browser accepts the specified CSS declaration.
For current compatibility information, visit Can I Use? and search for CSS progress() function.
Specifications
The progress() function is defined in the CSS Values and Units Module Level 5 .
The specification describes the function's arguments, range normalization, and mathematical evaluation.
Related CSS functions include calc(), clamp(), min(), max(), and abs().
