deleteRule CSSKeyframesRule 方法在 IE11 中混淆行为

2024-01-04

我使用 css @keyframes 创建了圆形的基本动画。 我正在使用 javascript 通过单击圆圈内来触发动画开始/停止。

动画本身可以分为 5 个(循环)阶段:
暂停-扩展-暂停-收缩-暂停(参见下面的@keyframes css部分)

我想要实现的目标最终是能够设置动画持续时间并更改关键帧的值(例如通过具有暂停和扩展/收缩持续时间的输入字段 - 细节对于这个问题的范围并不重要) 。我已经组合了一个 JavaScript 函数来执行此任务,并将其设置为onload只是为了测试它是如何工作的。

My HTML:

<!doctype html>
<html>
    <head>
        <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
        <meta content="utf-8" http-equiv="encoding">

        <link rel="stylesheet" href="style.css">
        <script src = "animation.js"></script>

    </head>
    <body onload=setAnimationDuration(1,1)>
        <div id="circle" class='circle-paused' onclick=cssAnimation()></div>
    </body>
</html>

My CSS:

#circle {
position: absolute;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
}

.circle-paused {
width: 9%;
padding-top: 9%;
border-radius: 50%;
background-color: #800080;
margin: auto;
}

.circle-animated {
/* 2 sec pause 4 sec expand_shrink*/
width: 9%;
padding-top: 9%;
-webkit-animation-name: my-circle; /* Safari 4.0 - 8.0 */
-webkit-animation-duration: 12s; /* Safari 4.0 - 8.0 */
animation-name: my-circle;
animation-duration: 12s;
animation-iteration-count: infinite;
animation-timing-function: linear;
border-radius: 50%;
margin: auto;
}

@keyframes my-circle {
0% {background-color: #800080; width: 9%; padding-top: 9%;}
33.3% {background-color: #D8BFD8; width: 28%; padding-top: 28%;}
50% {background-color: #D8BFD8; width: 28%; padding-top: 28%;}
83.3% {background-color: #800080; width: 9%; padding-top: 9%;}
100% {background-color: #800080; width: 9%; padding-top: 9%;}
}

我的 JavaScript:

function cssAnimation() {
  if (document.getElementById('circle').className == 'circle-paused') {
    document.getElementById('circle').className = 'circle-animated'
  } else {
    document.getElementById('circle').className = 'circle-paused'
  }
}


function findKeyframes(animation_name) {
  // get list of current keyframe rules
  var style_sheet = document.styleSheets;
  for (var i = 0; i < style_sheet.length; ++i) {
    for (var j = 0; j < style_sheet[i].cssRules.length; ++j) {
      // type 7 correspond to CSSRule.KEYFRAMES_RULE, for more info see https://developer.mozilla.org/en-US/docs/Web/API/CSSRule 
      if (style_sheet[i].cssRules[j].type == 7 && style_sheet[i].cssRules[j].name == animation_name) {
        return style_sheet[i].cssRules[j];
      }
    }
  }
  // keyframe rules were not found for given animation_name
  return null;
}


function getPercentage(total, fraction) {
  // Returns what percentage the fraction is from total
  // The result is rounded to 1 decimal place
  return Math.round(((100 / total) * fraction) * 10) / 10;
}


function setAnimationDuration(pause, expand_shrink) {
  var total_animation_duration = (pause * 2) + (expand_shrink * 2)
  var pause_percentage = getPercentage(total_animation_duration, pause)
  var expand_shrink_percentage = getPercentage(total_animation_duration, expand_shrink)

  var pause1 = pause_percentage + expand_shrink_percentage;
  var shrink = pause1 + expand_shrink_percentage;

  var frame_percentage_list = [0, expand_shrink_percentage, pause1, shrink, 100]

  var key_frame_list = findKeyframes('my-circle')
  var new_rule_list = []
  var to_be_removed_key_list = []

  //create array of new rules to be inserted
  //collecting old keys of rules to be deleted
  for(var i = 0; i < key_frame_list.cssRules.length; i++) {
    var current_rule = key_frame_list.cssRules[i].cssText

    to_be_removed_key_list.push(key_frame_list.cssRules[i].keyText)
    new_rule_list.push(current_rule.replace(/[+-]?([0-9]*[.])?[0-9]+%/, frame_percentage_list[i] + '%'))
  }

  // delete old rules
  for(var i = 0; i < to_be_removed_key_list.length; i++) {
    key_frame_list.deleteRule(to_be_removed_key_list[i])
  }

  // populate new ruels
  for(var i = 0; i < new_rule_list.length; i++) {
    key_frame_list.appendRule(new_rule_list[i])
  }


  document.getElementById('circle').style.animationDuration = total_animation_duration + "s"
}

上面的代码,在 JSFiddle 上 https://jsfiddle.net/mfo4qk9dv2ua5iksttbnqx64c/rpve2e9L/

问题本身:
该代码在 FireFox (55.0.3)、Chrome (61.0) 和 Safari (11.0) 中按预期工作。不过,当我开始在 IE11 中测试它时,我发现key_frame_list.deleteRule('rule_key')抛出一个Invalid argument错误。在研究这个问题时,我发现(并陷入困境)本文 http://usefulangle.com/post/39/adding-css-to-stylesheet-with-javascript(虽然它没有解决 IE 问题,但它提高了我对 css 动画的整体理解)。在 MSDN 上我找到了两个参考文献,涉及deleteRule: one https://msdn.microsoft.com/en-us/library/ff975162(v=vs.85).aspx and two https://msdn.microsoft.com/en-us/library/hh772386(v=vs.85).aspx。虽然我不太明白这是什么意思,但第二个 https://msdn.microsoft.com/en-us/library/hh772386(v=vs.85).aspx, by:

键必须解析为 0 到 1 之间的数字,否则规则将被忽略。

我假设在 IE 中你必须将索引传递给deleteRule而不是字符串键。所以我尝试在 IE 控制台中检查我的假设。这是我发现的(鉴于我的 js 代码位于 onload 中):

var key_frame_list = findKeyframes('my-circle')
key_frame_list.cssRules.length => 5
key_frame_list.deleteRule(0)
key_frame_list.cssRules.length => 4
key_frame_list.deleteRule(1)
key_frame_list.cssRules.length => 3
key_frame_list.deleteRule(0)
key_frame_list.deleteRule(1)
key_frame_list.deleteRule(2)
...
key_frame_list.cssRules.length => 3

正在发生的事情是:

key_frame_list.deleteRule(0)- 删除第一条规则(即 0%)
key_frame_list.deleteRule(1) - 删除最后一条规则(即 100%)
之后无论我传递到哪个索引key_frame_list.deleteRule() the key_frame_list.cssRules.length仍为 3。
我的期望是我能够再次出现key_frame_list.deleteRule(0)并删除所有规则(正如我预期的那样,索引会在每次规则删除后发生变化)。

现在,我想了解:

  1. 正确的使用方法是什么(基本上是“我做错了什么吗?”)deleteRule在 IE 中(或者是否应该使用其他方法)?
  2. 为什么我无法删除五个规则中的两个以上?
  3. 是否有一种适合此目的的方法可以在 Firefox、Chrome 和 IE11 上使用相同的参数,我不知道?

  1. What is the proper way (basically, 'Am I doing something wrong?') to use deleteRule in the IE (or if another method should be used)?

  2. 为什么我无法删除五个规则中的两个以上?

    第一个 MSDN 链接不适用;那deleteRule()方法适用于顶级规则,而不是关键帧规则。

    文本“密钥必须解析为 0 到 1 之间的数字,否则规则将被忽略。”第二个链接实际上取自2013 WD CSS 动画 https://www.w3.org/TR/css-animations/#CSSKeyframesRules-deleteRule,并且意味着 Internet Explorer 需要一个表示百分比的十进制数,而不是包含 0%-100% 关键帧选择器的字符串。该参数不代表索引。

    因此,对于 0% 关键帧规则,IE 期望值为 0;对于 100% 关键帧规则,IE 期望值为 1;对于 33.3% 关键帧规则,IE 期望浮点值 0.333:

    key_frame_list.deleteRule(0)     // Deletes the 0% keyframe rule
    key_frame_list.deleteRule(0.333) // Deletes the 33.3% keyframe rule
    key_frame_list.deleteRule(1)     // Deletes the 100% keyframe rule
    

    一旦 0% 规则被删除,如果没有 0% 规则剩余,则额外调用deleteRule(0)不会做任何事。

    由于关键帧不能超过 100%,deleteRule(2)毫无意义,因为这意味着删除 200% 关键帧规则,而该规则不可能存在。

  3. 是否有一种适合此目的的方法可以在 Firefox、Chrome 和 IE11 上使用相同的参数,我不知道?

    不; Internet Explorer 11 遵循 2013 WD(本身是在 Internet Explorer 10 发布后于 2012 年至 2013 年之间开发的),这意味着其实现与当前标准不一致,其中the deleteRule()方法已更改为接受字符串参数而不是数字参数 https://drafts.csswg.org/css-animations/#interface-csskeyframesrule-deleterule.

    这意味着 API 不兼容,因此没有干净的解决方法。您只需尝试这两个论点即可。我changed https://jsfiddle.net/BoltClock/8hzgbfxg/1你的小提琴中的以下声明:

    // delete old rules
    for(var i = 0; i < to_be_removed_key_list.length; i++) {
      key_frame_list.deleteRule(to_be_removed_key_list[i])
    }
    

    to:

    // delete old rules
    for(var i = 0; i < to_be_removed_key_list.length; i++) {
      try {
        key_frame_list.deleteRule(to_be_removed_key_list[i])
      } catch (e) {
        key_frame_list.deleteRule(+(parseFloat(to_be_removed_key_list[i]) / 100).toFixed(3))
      }
    }
    

    The +(parseFloat(to_be_removed_key_list[i]) / 100).toFixed(3)bit 将百分比字符串转换为数值,并考虑舍入误差。 IEEE-754 浮点数固有的舍入误差是 API 最初更改的原因(即与appendRule()方法总是期望一个字符串),除非它只改变了一段时间afterInternet Explorer 11 发布,自此IE11将不再接收平台更新 https://stackoverflow.com/questions/35184048/what-is-after-internet-explorer-11-on-windows-7-how-well-will-es2016-be-support/35184087#35184087,这意味着 IE11 仍停留在其旧的 WD 实现(我必须强调,它在开发时是最新的)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

deleteRule CSSKeyframesRule 方法在 IE11 中混淆行为 的相关文章

随机推荐