在动画暂停时使用j Query更改动画延迟在Safari上不起作用,但在其他任何地方都可以

Eri*_*utz 7 css safari jquery

我在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;
      }
    }
Run Code Online (Sandbox Code Playgroud)
   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);
      }
    }
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

我现在用谷歌搜索了几个小时,但我不知道可能是什么问题.任何的想法?

Oll*_*han 1

经过大量实验后,这里有一个包含解决方法的版本,可以在Safari 11.1.2 和 Chrome 68(希望其他浏览器也能)中提供流畅、预期的行为。

正如问题所述,根本问题似乎是当暂停动画的动画属性发生更改时,元素不会重新绘制。该解决方案通过在每帧重新添加必要的动画相关 CSS(具有正确的延迟)来解决这个问题。这通常会导致闪烁(因为当动画被删除时,Safari 会尝试恢复为无动画样式),因此此解决方案每次修改动画时都会手动应用当前的动画样式。

$(document).ready(function() {
  fluider([{
      selector: '.manualAnim',
      start: 100,
      end: 500
    },

    {
      selector: '.manualAnim2',
      start: 500,
      end: 1000
    },

    {
      selector: '.manualAnim3',
      start: 0,
      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);
    }
  });
}
Run Code Online (Sandbox Code Playgroud)
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);
  }
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)