纯 CSS 无法实现滚动驱动的 background-color 变化,因 scroll-driven animation 规范不支持该属性;必须用 JS 计算归一化滚动进度并更新 CSS 变量,再通过 hsl() 或 color-mix() 实现平滑变色。

纯 CSS 无法真正实现随滚动进度变化的 background-color——@scroll-timeline 不支持该属性,浏览器会静默忽略或 fallback 到时间线播放,和滚动无关。必须用 JS 驱动 CSS 变量 + hsl() 或 color-mix() 实现平滑、可控的变色。
为什么不能直接动画 background-color
Chrome 126+、Firefox 119+ 明确不支持 background-color 在 scroll-driven animation 中插值。规范只允许动画 opacity、transform、部分 filter 和 clip-path。你写的 @keyframes + @scroll-timeline 对颜色无效,看到的“变化”其实是退回到默认时间线播放的结果。
滚动进度怎么算才不出错
错误写法:window.scrollY / document.documentElement.scrollHeight —— 因为 scrollHeight 包含不可见 padding/border,拉到底部时结果永远
正确公式需防零、防溢出、适配移动端橡皮筋:
立即学习“前端免费学习笔记(深入)”;
const maxScroll = Math.max(document.documentElement.scrollHeight - window.innerHeight, 1)const progress = Math.min(1, Math.max(0, window.scrollY / maxScroll))- 必须用
requestAnimationFrame节流,避免高频重排;缓存scrollHeight和clientHeight,只在DOMContentLoaded或resize后更新 - iOS Safari 滚动可能超出合法范围(如
window.scrollY为负),要额外Math.max(0, ...)clamp
JS 更新变量 + CSS 声明 transition 才真平滑
直接写 element.style.backgroundColor = '...' 会导致跳变、卡顿,尤其在低端安卓机上明显。
可靠路径是:
- JS 用
document.documentElement.style.setProperty('--bg-progress', progress)更新变量(注意双横线前缀) - CSS 中消费它:
background: hsl(220, 90%, calc(95% - var(--bg-progress) * 85%)); - 必须声明
transition: background 0.4s ease;(不是background-color,因为hsl()是 background 的值) - 别用
rgb():三通道分别插值极易偏色;hsl()只动L(亮度)参数,视觉过渡自然,且现代浏览器解析高效
容易被忽略的细节
变量名拼错(比如写成 --bgprogress)、CSS 里漏掉 hsl() 或 calc()、传值带 % 单位、L 值设到 0% 或 100% 导致暗色模式下不可见——这些都会让变色失效或突变。最稳的组合是:节流 + 缓存 + clamp + hsl() + transition: background。


















