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

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

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

我的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>


我的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"
}


Code above, on JSFiddle

问题本身:
该代码可以在FireFox(55.0.3),Chrome(61.0)和Safari(11.0)中正常工作。但是,当我开始在IE11中对其进行测试时,我发现key_frame_list.deleteRule('rule_key')引发了Invalid argument错误。在研究该问题时,我发现了(并且走出了)this article(尽管它不能解决IE问题,但可以提高我对CSS动画的整体理解)。在MSDN上,我找到了两个与deleteRule有关的参考:onetwo。尽管我不太了解the second one中的含义:


  键必须解析为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()key_frame_list.cssRules.length都保持为3。
我的期望是,我将能够再次使用key_frame_list.deleteRule(0)并删除所有规则(因为我希望每次删除规则后索引都会移动)。

现在,我想了解:


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

最佳答案

在IE中使用deleteRule的正确方法(基本上是“我做错了吗?”)(或者是否应该使用其他方法)是什么?


  为什么我不能删除五个规则中的两个以上规则?


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

文本“密钥必须解析为0到1之间的数字,否则规则将被忽略。”实际上,第二个链接中的“第二个链接”来自2013 WD of css-animations,这意味着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%关键帧规则,该规则不存在。

  我不知道有没有适合此目的的方法,可以在Firefox,Chrome和IE11上使用相同的参数?


没有; Internet Explorer 11遵循2013 WD(它是在Internet Explorer 10发布后于2012年至2013年之间开发的),这意味着其实现与当前的the deleteRule() method has been changed to accept a string argument instead of a numeric argument标准不一致。

这意味着API不兼容,因此没有干净的解决方法。您只需要尝试两个参数。我在您的提琴中changed以下声明:

// 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])
}


至:

// 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))
  }
}


+(parseFloat(to_be_removed_key_list[i]) / 100).toFixed(3)位将百分比字符串转换为数值,同时考虑到舍入错误。 IEEE-754浮点数固有的舍入错误是首先更改API的原因(与一直期望使用字符串的appendRule()方法保持一致),原因是仅更改了一段时间在Internet Explorer 11发布之后,并且从IE11 will no longer receive platform updates开始,这意味着IE11仍旧使用其旧的WD实现(我必须强调,它是在其开发时是最新的)。

10-08 20:16