我在CSS中设置了一个关键帧动画.将其附加到DOM元素并将其设置为暂停.使用
javascript(jQuery),我将动画延迟从0s更改为100s,在滚动时实现了漂亮的动画效果.
这适用于所有浏览器,但不适用于Safari(版本11.1.1(13605.2.8)).
$(document).ready(function() { fluider([ { selector: '.manualAnim',start: 100,end: 500 },{ selector: '.manualAnim2',start: 500,end: 1000 },{ selector: '.manualAnim3',start: 0,end: 1500 } ]) }) function fluider(o) { for(var i = 0; i < o.length; i++) { $(o[i].selector).css('animation-play-state','paused'); $(o[i].selector).css('animation-duration','100s'); } $(window).scroll(function() { var h = $(window).scrollTop(); for(var i = 0; i < o.length; i++) { $(o[i].selector).css('animation-delay',-clamp(0,100,((h-o[i].start)/o[i].end * 100)) + 's'); } }); } function clamp(from,to,val) { if(val >= from) { if(val <= to) { return val; } else { return to; } } else { return from; } }
body { height: 1000vh; } .manualAnim { position: fixed; display: block; width: 100px; height: 100px; background-color: red; animation: 100s anim paused both; animation-delay: 0s; } .manualAnim2 { position: fixed; display: block; left: 120px; width: 100px; height: 100px; background-color: red; animation: 100s anim paused both; animation-delay: 0s; } .manualAnim3 { position: fixed; display: block; left: 240px; width: 100px; height: 100px; background-color: red; animation: 100s anim paused both; animation-delay: 0s; } @keyframes anim{ 0% { background-color: red; transform: scale(1); } 30% { background-color: green; transform: scale(1.5); } 60% { background-color: blue; transform: scale(0.5); } 100% { background-color: yellow; transform: scale(1); } }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div class="manualAnim"></div> <div class="manualAnim2"></div> <div class="manualAnim3"></div>
我现在用谷歌搜索几个小时,但我不知道可能是什么问题.
任何的想法?
解决方法
经过大量的实验,这里有一个带有变通方法的版本,可以在Safari 11.1.2和Chrome 68(以及其他浏览器)中提供平滑,预期的行为.
看起来潜在的问题是,当为暂停的动画更改动画属性时,元素不会重新绘制,正如问题所述.这个解决方案通过每帧重新添加必要的动画相关CSS(具有正确的延迟)来解决这个问题.这通常会导致闪烁(因为Safari会在删除动画时尝试恢复到非动画样式),因此每次修改动画时此解决方案都会手动应用当前动画样式.
$(document).ready(function() { fluider([{ selector: '.manualAnim',end: 500 },{ selector: '.manualAnim2',end: 1000 },{ selector: '.manualAnim3',end: 1500 } ]) }) function getAnimatedProperties(animName) { // Get an array of all property names that // are modified by the animation ${animName} let properties = {}; let sheets = document.styleSheets; let propertyRegex = /([a-z\-]+):/ig; for (let sheet of sheets) { let rules = sheet.rules || sheet.cssRules; for (let r of rules) { if (r.name === animName) { let rText = r.cssText; let match = propertyRegex.exec(rText); while (match) { properties[match[1]] = true; match = propertyRegex.exec(rText); } } } } return Object.keys(properties); } function fluider(o) { const animationName = "anim"; const preservedProperties = getAnimatedProperties(animationName); $(window).scroll(function() { var h = $(window).scrollTop(); for (var i = 0; i < o.length; i++) { let el = document.querySelector(o[i].selector); let pct = 100 * (parseInt(h) - o[i].start) / o[i].end; let delay = -Math.max(Math.min(pct,100),0) + 's'; let s = window.getComputedStyle(el); // without setting these properties and overwriting .style,// the animation will flicker let preservedStyles = preservedProperties.map(p => `${p}: ${s[p]};`).join(""); el.style = `${preservedStyles} animation-delay: ${delay}; animation-duration: 100s; animation-play-state: paused;`; // without scheduling this *using setTimeout*,// the animation will not rerender window.setTimeout(() => { el.style.animationName = animationName; },0); } }); }
body { height: 1000vh; } .manualAnim { position: fixed; display: block; width: 100px; height: 100px; background-color: red; } .manualAnim2 { position: fixed; display: block; left: 120px; width: 100px; height: 100px; background-color: red; } .manualAnim3 { position: fixed; display: block; left: 240px; width: 100px; height: 100px; background-color: red; } @keyframes anim { 0% { background-color: red; transform: scale(1); } 30% { background-color: green; transform: scale(1.5); } 60% { background-color: blue; transform: scale(0.5); } 100% { background-color: yellow; transform: scale(1); } }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div class="manualAnim"></div> <div class="manualAnim2"></div> <div class="manualAnim3"></div>