2

我用css @keyframes创建了一个圆的基本动画。 我使用javascript通过点击圆圈内部触发动画开始/停止。deleteRule CSSKeyframesRule方法在IE11中混淆了行为

动画本身可分为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上,我找到两个参考文献,涉及deleteRuleonetwo。虽然我并没有真正理解什么意思,在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)复发并删除所有规则(因为我预计索引将在每次删除规则后发生变化)。现在

,我想明白了:

  1. 什么是正确的方式(基本上,“?难道我做错了什么”)在IE使用deleteRule(或是否应使用另一种方法) ?
  2. 为什么我无法删除五个以上的两个规则?
  3. 有没有一种方法适用于这个目的,将在Firefox,Chrome和IE11上使用相同的参数,我不知道?

回答

3
  1. 什么是正确的方式(基本上,“难道我做错了什么?”)在IE使用deleteRule(或是否应使用另一种方法)?

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

    第一个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%关键帧规则。

  3. 是否有适合此目的的方法,可以在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实现(我必须强调的是它在开发时是最新的)实施。