你以为 CSS 只能算数学?今天 progress() 把这件事彻底变成了比例尺

写响应式 CSS 的时候,你有没有遇到过这种尴尬:想根据视口宽度让图片透明度从 1 慢慢降到 0.4,或者让标题大小在 480px 到 1200px 之间顺滑过渡,以前只能写一长串 calc() 嵌套,或者干脆写几个断点完事。Chrome 138 就上了这个 API,但 Firefox 一直缺席——直到今年九月 Firefox 155 稳定版发布,progress() 终于在四大浏览器全部就位,Baseline 2026,正式成为生产可用的 CSS 新原语。

progress() 做什么?它本质上是一个 unit-agnostic(单位无关)的 0~1 插值器。你扔进去一个值和它的上下界,它返回这个值落在区间里的比例:

progress(当前值, 起始值, 结束值)

返回的是 0 到 1 之间的数字。低于起始值返回 0,高于结束值返回 1,中间值按比例返回小数。你可以拿这个比例去做 opacity、scale、color 插值,或者塞进 calc() 做更复杂的运算。

最直观的应用是流体透明度——以前要写这样的 calc 表达式才能实现视口越窄图片越透明:

/ 以前:混合单位根本没法直接写 /
opacity: clamp(0.4, 1 – ((100vw – 480px) / (1200px – 480px)) * 0.6, 1);

/ 现在:progress() 直接替你算比例 /
.hero img {
opacity: clamp(0.4, 1 – progress(100vw, 480px, 1200px) * 0.6, 1);
}

视口宽度 ≤ 480px 时,progress() 返回 0,opacity = 1;视口宽度 ≥ 1200px 时,progress() 返回 1,opacity = 0.4;中间宽度顺滑过渡。关键是它可以直接混用 100vw(视口单位)和 px(像素单位),这是以前纯 calc() 做不到的事情。

再举一个实用例子:根据容器宽度让一个卡片等比放大:

.card {
transform: scale(calc(1 + progress(var(–container-width), 300px, 700px) * 0.1));
}

容器宽度从 300px 到 700px,卡片 scale 从 1.0 慢慢变到 1.1,完全不用写媒体查询。

progress() 还有个 no-clamp 关键字,意思是不把结果限制在 0~1 范围内,让它可以超出:

/ no-clamp: 值超出边界时比例可以超过 1 或低于 0 /
scale: progress(no-clamp 15, 0, 10); / 返回 1.5 /
scale: progress(no-clamp -5, 0, 10); / 返回 -0.5 /

这个在需要溢出效果的场景很有用,比如拖动条拖过头时的弹性放大。

浏览器支持现状(2026 年 9 月)

Firefox 155 稳定版刚发布(2026 年 9 月 1 日),意味着 progress() 现在 Chrome 138+、Firefox 155+、Safari 26+、Edge 138+ 全部支持,全球覆盖率超过 85%,已经是 Baseline 2026 的安全特性。Safari 从 26 就开始支持了,Chrome 138(2025 年 6 月)跟进,现在 Firefox 补齐最后一块拼图。

渐进增强写法:

/ 先写 fallback,确保老浏览器也有合理体验 /
h1 {
font-size: clamp(1.5rem, 1rem + 2vw, 3rem);
}

/ 然后用 @supports 叠一层 progress() 增强 /
@supports (progress(100vw, 360px, 1200px)) {
h1 {
font-size: calc(1.5rem + 1.5rem * progress(100vw, 360px, 1200px));
}
}

什么时候用 progress() 而不是 clamp()?

简单总结:只是限制上下界,用 clamp() 就够了;要把一个值转成 0~1 的进度再去做其他计算(比如映射到颜色、透明度、scale),就用 progress() + calc()。两者可以配合使用,progress() 负责把值归一化,clamp() 负责把结果限制在合理范围。

三个可以立刻上手的下一步

  1. 把某个响应式效果从媒体查询迁移到 progress():找一个写了 min-width 断点的效果,试试看用 progress(100vw, …px, …px) 替代断点,让过渡变成连续曲线而不是跳变。

  2. 给阅读进度条加上 color-mix() 颜色插值:background: color-mix(in srgb, #6366f1 calc(100% * progress(var(–read-progress), 0, 1)), #f97316);,进度条颜色从橙色渐变到蓝紫色,全程零 JS。

  3. 用 @supports 做渐进增强:现在就可以把 progress() 用在生产项目里,写一个 @supports fallback,确保 Firefox 155 以下的用户也有基础体验。

progress() 本质上是把 CSS 带进了图形编程里的 smoothstep() 思维——游戏引擎里用来做平滑过渡的函数,终于进了浏览器。以后做响应式效果、设计系统里的流体 token、滚动驱动动画,可以少写很多 JS 和复杂 calc,多用几行声明式 CSS 就够了。

评论区

0 条评论

登录后可评论。