如何基于滚动位置使用CSS动画实现效果,替代复杂JS计算?
实现方案:基于CSS滚动驱动动画替代JS样式计算
你要的效果可以直接通过**CSS原生滚动驱动动画(Scroll-driven Animations)**实现,完全不需要在JS中做复杂的样式计算,也不用维护大量内联样式,性能比原有实现高很多。
核心实现逻辑
你原来的逻辑是滚动距离0~125px对应各个元素的样式线性变化,我们可以直接把这个变化逻辑映射为CSS关键帧动画,绑定横向滚动作为动画进度的驱动源即可。
第一步:编写CSS动画逻辑
/* 滚动容器配置 */ .scroll-container { position: relative; width: 100%; overflow-x: auto; scrollbar-width: none; /* 定义横向滚动时间线 */ scroll-timeline: --scroll-timeline x; timeline-scope: --scroll-timeline; } .scroll-container::-webkit-scrollbar { display: none; } /* wrapper元素动画 */ @keyframes wrapperAnimation { 0% { height: 215px; width: 130px; border-bottom-left-radius: 0; border-bottom-right-radius: 15px; border-top-left-radius: 0; border-top-right-radius: 15px; padding-top: 0; } 100% { height: calc(215px - 125px / 0.75); width: calc(130px - 125px / 1.7); border-bottom-right-radius: calc(15px + 125px / 8); border-top-right-radius: calc(15px + 125px / 8); padding-top: calc(125px / 15.5); } } .add-wrapper { animation: wrapperAnimation linear both; animation-timeline: --scroll-timeline; /* 滚动0~125px对应动画从0到100%进度 */ animation-range: 0 125px; } /* 图片元素动画 */ @keyframes imageAnimation { 0% { height: 166px; width: 166px; border-radius: 0; } 100% { height: calc(166px - 125px / 0.92); width: calc(166px - 125px / 0.92); border-radius: calc(125px / 2); } } .add-image { animation: imageAnimation linear both; animation-timeline: --scroll-timeline; animation-range: 0 125px; } /* 加号元素动画 */ @keyframes plusAnimation { 0% { margin-right: 0; height: 25px; width: 25px; border-width: 1px; right: 0; margin-left: 0; } 100% { margin-right: calc(125px / 4); height: calc(25px - 125px / 16); width: calc(25px - 125px / 16); right: calc(125px / 7); margin-left: calc(125px / 32); } } .add-plus { animation: plusAnimation linear both; animation-timeline: --scroll-timeline; animation-range: 0 125px; } /* 文本元素动画 */ @keyframes textAnimation { 0% { opacity: 1; } 100% { opacity: 0.08; } } .add-text { animation: textAnimation linear both; animation-timeline: --scroll-timeline; animation-range: 0 125px; }
第二步:简化React逻辑
不需要再维护scrollPosition状态和大量内联样式,只需要保留按钮切换的滚动监听即可:
const pager = React.createRef(); const toggleNextBtn = () => { /* 保留原有按钮切换逻辑 */ } const update = () => { toggleNextBtn(); } return ( <div ref={pager} onScroll={update} className="scroll-container"> <div className="add-wrapper"> <img className="add-image" alt="" /> <div className="add-plus">+</div> <p className="add-text">文本内容</p> </div> {/* 其他原有业务内容 */} </div> )
方案优势
- 所有样式计算交由浏览器原生处理,没有JS监听滚动更新状态带来的额外重渲染开销,动画全程无掉帧
- 样式逻辑统一放在CSS中,可维护性远高于JS写内联样式,调整参数不需要修改JS代码
- 完全匹配你原来的交互效果,不需要做额外的逻辑适配
- 如果需要兼容低版本浏览器,引入对应polyfill即可,不需要修改业务逻辑
内容的提问来源于stack exchange,提问作者Chris Chilcoat
相关产品推荐
相关产品推荐

