我已经使用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
有关的参考:one和two。尽管我不太了解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实现(我必须强调,它是在其开发时是最新的)。