// Test that animations don't affect the computed value before the
// start of the animation or after its end. Test without
// animation-fill-mode, but then repeat the test with all the values of
// animation-fill-mode.
function test_fill_mode(fill_mode, fills_backwards, fills_forwards)
{ varstyle = "margin-left: 30px; animation: 10s 3s anim1 linear"; var desc;
if (fill_mode.length > 0) { style += " " + fill_mode;
desc = "fill mode " + fill_mode + ": ";
} else {
desc = "default fill mode: ";
}
new_div(style);
listen();
if (fills_backwards)
is(cs.marginLeft, "0px", desc + "does affect value during delay (0s)");
else
is(cs.marginLeft, "30px", desc + "doesn't affect value during delay (0s)");
advance_clock(2000);
if (fills_backwards)
is(cs.marginLeft, "0px", desc + "does affect value during delay (2s)");
else
is(cs.marginLeft, "30px", desc + "doesn't affect value during delay (2s)");
check_events([], "before start in test_fill_mode");
advance_clock(1000);
check_events([{ type: 'animationstart', target: div,
bubbles: true, cancelable: false,
animationName: 'anim1', elapsedTime: 0.0,
pseudoElement: "" }], "right after start in test_fill_mode");
if (fills_backwards)
is(cs.marginLeft, "0px", desc + "affects value at start of animation");
advance_clock(125);
is(cs.marginLeft, "2px", desc + "affects value during animation");
advance_clock(2375);
is(cs.marginLeft, "40px", desc + "affects value during animation");
advance_clock(2500);
is(cs.marginLeft, "80px", desc + "affects value during animation");
advance_clock(2500);
is(cs.marginLeft, "90px", desc + "affects value during animation");
advance_clock(2375);
is(cs.marginLeft, "99.5px", desc + "affects value during animation");
check_events([], "before end in test_fill_mode");
advance_clock(125);
check_events([{ type: 'animationend', target: div,
bubbles: true, cancelable: false,
animationName: 'anim1', elapsedTime: 10.0,
pseudoElement: "" }], "right after end in test_fill_mode");
if (fills_forwards)
is(cs.marginLeft, "100px", desc + "affects value at end of animation");
advance_clock(10);
if (fills_forwards)
is(cs.marginLeft, "100px", desc + "does affect value after animation");
else
is(cs.marginLeft, "30px", desc + "does not affect value after animation");
done_div();
}
test_fill_mode("", false, false);
test_fill_mode("none", false, false);
test_fill_mode("forwards", false, true);
test_fill_mode("backwards", true, false);
test_fill_mode("both", true, true);
// Test that animations continue running when the animation name
// list is changed.
new_div("animation: anim1 linear 10s");
is(cs.getPropertyValue("margin-top"), "0px", "just anim1, margin-top at start");
is(cs.getPropertyValue("margin-right"), "0px", "just anim1, margin-right at start");
is(cs.getPropertyValue("margin-bottom"), "0px", "just anim1, margin-bottom at start");
is(cs.getPropertyValue("margin-left"), "0px", "just anim1, margin-left at start");
advance_clock(1000);
is(cs.getPropertyValue("margin-top"), "0px", "just anim1, margin-top at 1s");
is(cs.getPropertyValue("margin-right"), "0px", "just anim1, margin-right at 1s");
is(cs.getPropertyValue("margin-bottom"), "0px", "just anim1, margin-bottom at 1s");
is(cs.getPropertyValue("margin-left"), "16px", "just anim1, margin-left at 1s");
// append anim2 div.style.animation = "anim1 linear 10s, anim2 linear 10s";
is(cs.getPropertyValue("margin-top"), "0px", "anim1 + anim2, margin-top at 1s");
is(cs.getPropertyValue("margin-right"), "0px", "anim1 + anim2, margin-right at 1s");
is(cs.getPropertyValue("margin-bottom"), "0px", "anim1 + anim2, margin-bottom at 1s");
is(cs.getPropertyValue("margin-left"), "16px", "anim1 + anim2, margin-left at 1s");
advance_clock(1000);
is(cs.getPropertyValue("margin-top"), "0px", "anim1 + anim2, margin-top at 2s");
is(cs.getPropertyValue("margin-right"), "10px", "anim1 + anim2, margin-right at 2s");
is(cs.getPropertyValue("margin-bottom"), "0px", "anim1 + anim2, margin-bottom at 2s");
is(cs.getPropertyValue("margin-left"), "32px", "anim1 + anim2, margin-left at 2s");
// prepend anim3 div.style.animation = "anim3 linear 10s, anim1 linear 10s, anim2 linear 10s";
is(cs.getPropertyValue("margin-top"), "0px", "anim3 + anim1 + anim2, margin-top at 2s");
is(cs.getPropertyValue("margin-right"), "10px", "anim3 + anim1 + anim2, margin-right at 2s");
is(cs.getPropertyValue("margin-bottom"), "0px", "anim3 + anim1 + anim2, margin-bottom at 2s");
is(cs.getPropertyValue("margin-left"), "32px", "anim3 + anim1 + anim2, margin-left at 2s");
advance_clock(1000);
is(cs.getPropertyValue("margin-top"), "10px", "anim3 + anim1 + anim2, margin-top at 3s");
is(cs.getPropertyValue("margin-right"), "20px", "anim3 + anim1 + anim2, margin-right at 3s");
is(cs.getPropertyValue("margin-bottom"), "0px", "anim3 + anim1 + anim2, margin-bottom at 3s");
is(cs.getPropertyValue("margin-left"), "48px", "anim3 + anim1 + anim2, margin-left at 3s");
// remove anim2 from end div.style.animation = "anim3 linear 10s, anim1 linear 10s";
is(cs.getPropertyValue("margin-top"), "10px", "anim3 + anim1, margin-top at 3s");
is(cs.getPropertyValue("margin-right"), "0px", "anim3 + anim1, margin-right at 3s");
is(cs.getPropertyValue("margin-bottom"), "0px", "anim3 + anim1, margin-bottom at 3s");
is(cs.getPropertyValue("margin-left"), "48px", "anim3 + anim1, margin-left at 3s");
advance_clock(1000);
is(cs.getPropertyValue("margin-top"), "20px", "anim3 + anim1, margin-top at 4s");
is(cs.getPropertyValue("margin-right"), "0px", "anim3 + anim1, margin-right at 4s");
is(cs.getPropertyValue("margin-bottom"), "0px", "anim3 + anim1, margin-bottom at 4s");
is(cs.getPropertyValue("margin-left"), "64px", "anim3 + anim1, margin-left at 4s");
// swap anim1 and anim3, change duration of anim3 div.style.animation = "anim1 linear 10s, anim3 linear 5s";
is(cs.getPropertyValue("margin-top"), "40px", "anim1 + anim3, margin-top at 4s");
is(cs.getPropertyValue("margin-right"), "0px", "anim1 + anim3, margin-right at 4s");
is(cs.getPropertyValue("margin-bottom"), "0px", "anim1 + anim3, margin-bottom at 4s");
is(cs.getPropertyValue("margin-left"), "64px", "anim1 + anim3, margin-left at 4s");
advance_clock(1000);
is(cs.getPropertyValue("margin-top"), "60px", "anim1 + anim3, margin-top at 5s");
is(cs.getPropertyValue("margin-right"), "0px", "anim1 + anim3, margin-right at 5s");
is(cs.getPropertyValue("margin-bottom"), "0px", "anim1 + anim3, margin-bottom at 5s");
is(cs.getPropertyValue("margin-left"), "80px", "anim1 + anim3, margin-left at 5s");
// list anim1 twice, last duration wins, original start time still applies div.style.animation = "anim1 linear 10s, anim3 linear 5s, anim1 linear 20s";
is(cs.getPropertyValue("margin-top"), "60px", "anim1 + anim3 + anim1, margin-top at 5s");
is(cs.getPropertyValue("margin-right"), "0px", "anim1 + anim3 + anim1, margin-right at 5s");
is(cs.getPropertyValue("margin-bottom"), "0px", "anim1 + anim3 + anim1, margin-bottom at 5s");
is(cs.getPropertyValue("margin-left"), "40px", "anim1 + anim3 + anim1, margin-left at 5s");
// drop one of the anim1, and list anim5 as well, which animates
// the same property as anim1 div.style.animation = "anim3 linear 5s, anim1 linear 20s, anim5 linear 10s";
is(cs.getPropertyValue("margin-top"), "60px", "anim3 + anim1 + anim5, margin-top at 5s");
is(cs.getPropertyValue("margin-right"), "0px", "anim3 + anim1 + anim5, margin-right at 5s");
is(cs.getPropertyValue("margin-bottom"), "0px", "anim3 + anim1 + anim5, margin-bottom at 5s");
is(cs.getPropertyValue("margin-left"), "0px", "anim3 + anim1 + anim5, margin-left at 5s");
advance_clock(1000);
is(cs.getPropertyValue("margin-top"), "80px", "anim3 + anim1 + anim5, margin-top at 6s");
is(cs.getPropertyValue("margin-right"), "0px", "anim3 + anim1 + anim5, margin-right at 6s");
is(cs.getPropertyValue("margin-bottom"), "0px", "anim3 + anim1 + anim5, margin-bottom at 6s");
is(cs.getPropertyValue("margin-left"), "10px", "anim3 + anim1 + anim5, margin-left at 6s");
// now swap the anim5 and anim1 order div.style.animation = "anim3 linear 5s, anim5 linear 10s, anim1 linear 20s";
is(cs.getPropertyValue("margin-top"), "80px", "anim3 + anim1 + anim5, margin-top at 6s");
is(cs.getPropertyValue("margin-right"), "0px", "anim3 + anim1 + anim5, margin-right at 6s");
is(cs.getPropertyValue("margin-bottom"), "0px", "anim3 + anim1 + anim5, margin-bottom at 6s");
is(cs.getPropertyValue("margin-left"), "48px", "anim3 + anim1 + anim5, margin-left at 6s");
advance_clock(1000);
is(cs.getPropertyValue("margin-top"), "0px", "anim3 + anim1 + anim5, margin-top at 7s");
is(cs.getPropertyValue("margin-right"), "0px", "anim3 + anim1 + anim5, margin-right at 7s");
is(cs.getPropertyValue("margin-bottom"), "0px", "anim3 + anim1 + anim5, margin-bottom at 7s");
is(cs.getPropertyValue("margin-left"), "56px", "anim3 + anim1 + anim5, margin-left at 7s");
// swap anim1 and anim5 back div.style.animation = "anim3 linear 5s, anim1 linear 20s, anim5 linear 10s";
is(cs.getPropertyValue("margin-top"), "0px", "anim3 + anim1 + anim5, margin-top at 7s");
is(cs.getPropertyValue("margin-right"), "0px", "anim3 + anim1 + anim5, margin-right at 7s");
is(cs.getPropertyValue("margin-bottom"), "0px", "anim3 + anim1 + anim5, margin-bottom at 7s");
is(cs.getPropertyValue("margin-left"), "20px", "anim3 + anim1 + anim5, margin-left at 7s");
advance_clock(100);
is(cs.getPropertyValue("margin-top"), "0px", "anim3 + anim1 + anim5, margin-top at 7.1s");
// Change the animation fill mode on the completed animation. div.style.animation = "anim3 linear 5s forwards, anim1 linear 20s, anim5 linear 10s";
is(cs.getPropertyValue("margin-top"), "100px", "anim3 + anim1 + anim5, margin-top at 7.1s, with fill mode");
advance_clock(900);
is(cs.getPropertyValue("margin-top"), "100px", "anim3 + anim1 + anim5, margin-top at 8s, with fill mode");
// Change the animation duration on the completed animation, so it is
// no longer completed. div.style.animation = "anim3 linear 10s, anim1 linear 20s, anim5 linear 10s";
is(cs.getPropertyValue("margin-top"), "60px", "anim3 + anim1 + anim5, margin-top at 8s, with fill mode");
is(cs.getPropertyValue("margin-left"), "30px", "anim3 + anim1 + anim5, margin-left at 8s");
done_div();
// Test the rules on keyframes that lack a 0% or 100% rule:
// (simultaneously, test that reverse animations have their keyframes
// run backwards)
// 100px at 0%, 50px at 50%, 150px at 100%
new_div("margin-top: 100px; animation: kf1 ease 1s alternate infinite");
is(cs.marginTop, "100px", "no-0% at 0.0s");
advance_clock(100);
is_approx(px_to_num(cs.marginTop), 100 - 50 * gTF.ease(0.2), 0.01, "no-0% at 0.1s");
advance_clock(200);
is_approx(px_to_num(cs.marginTop), 100 - 50 * gTF.ease(0.6), 0.01, "no-0% at 0.3s");
advance_clock(200);
is(cs.marginTop, "50px", "no-0% at 0.5s");
advance_clock(200);
is_approx(px_to_num(cs.marginTop), 50 + 100 * gTF.ease(0.4), 0.01, "no-0% at 0.7s");
advance_clock(200);
is_approx(px_to_num(cs.marginTop), 50 + 100 * gTF.ease(0.8), 0.01, "no-0% at 0.9s");
advance_clock(100);
is(cs.marginTop, "150px", "no-0% at 1.0s");
advance_clock(100);
is_approx(px_to_num(cs.marginTop), 50 + 100 * gTF.ease(0.8), 0.01, "no-0% at 1.1s");
advance_clock(300);
is_approx(px_to_num(cs.marginTop), 50 + 100 * gTF.ease(0.2), 0.01, "no-0% at 1.4s");
advance_clock(300);
is_approx(px_to_num(cs.marginTop), 100 - 50 * gTF.ease(0.6), 0.01, "no-0% at 1.7s");
advance_clock(200);
is_approx(px_to_num(cs.marginTop), 100 - 50 * gTF.ease(0.2), 0.01, "no-0% at 1.9s");
advance_clock(100);
is(cs.marginTop, "100px", "no-0% at 2.0s");
done_div();
// 150px at 0%, 50px at 50%, 100px at 100%
new_div("margin-top: 100px; animation: kf2 ease-in 1s alternate infinite");
is(cs.marginTop, "150px", "no-100% at 0.0s");
advance_clock(100);
is_approx(px_to_num(cs.marginTop), 150 - 100 * gTF.ease_in(0.2), 0.01, "no-100% at 0.1s");
advance_clock(200);
is_approx(px_to_num(cs.marginTop), 150 - 100 * gTF.ease_in(0.6), 0.01, "no-100% at 0.3s");
advance_clock(200);
is(cs.marginTop, "50px", "no-100% at 0.5s");
advance_clock(200);
is_approx(px_to_num(cs.marginTop), 50 + 50 * gTF.ease_in(0.4), 0.01, "no-100% at 0.7s");
advance_clock(200);
is_approx(px_to_num(cs.marginTop), 50 + 50 * gTF.ease_in(0.8), 0.01, "no-100% at 0.9s");
advance_clock(100);
is(cs.marginTop, "100px", "no-100% at 1.0s");
advance_clock(100);
is_approx(px_to_num(cs.marginTop), 50 + 50 * gTF.ease_in(0.8), 0.01, "no-100% at 1.1s");
advance_clock(300);
is_approx(px_to_num(cs.marginTop), 50 + 50 * gTF.ease_in(0.2), 0.01, "no-100% at 1.4s");
advance_clock(300);
is_approx(px_to_num(cs.marginTop), 150 - 100 * gTF.ease_in(0.6), 0.01, "no-100% at 1.7s");
advance_clock(200);
is_approx(px_to_num(cs.marginTop), 150 - 100 * gTF.ease_in(0.2), 0.01, "no-100% at 1.9s");
advance_clock(100);
is(cs.marginTop, "150px", "no-100% at 2.0s");
done_div();
// 50px at 0%, 100px at 25%, 50px at 100%
new_div("margin-top: 50px; animation: kf3 ease-out 1s alternate infinite");
is(cs.marginTop, "50px", "no-0%-no-100% at 0.0s");
advance_clock(50);
is_approx(px_to_num(cs.marginTop), 50 + 50 * gTF.ease_out(0.2), 0.01, "no-0%-no-100% at 0.05s");
advance_clock(100);
is_approx(px_to_num(cs.marginTop), 50 + 50 * gTF.ease_out(0.6), 0.01, "no-0%-no-100% at 0.15s");
advance_clock(100);
is(cs.marginTop, "100px", "no-0%-no-100% at 0.25s");
advance_clock(300);
is_approx(px_to_num(cs.marginTop), 100 - 50 * gTF.ease_out(0.4), 0.01, "no-0%-no-100% at 0.55s");
advance_clock(300);
is_approx(px_to_num(cs.marginTop), 100 - 50 * gTF.ease_out(0.8), 0.01, "no-0%-no-100% at 0.85s");
advance_clock(150);
is(cs.marginTop, "50px", "no-0%-no-100% at 1.0s");
advance_clock(150);
is_approx(px_to_num(cs.marginTop), 100 - 50 * gTF.ease_out(0.8), 0.01, "no-0%-no-100% at 1.15s");
advance_clock(450);
is_approx(px_to_num(cs.marginTop), 100 - 50 * gTF.ease_out(0.2), 0.01, "no-0%-no-100% at 1.6s");
advance_clock(250);
is_approx(px_to_num(cs.marginTop), 50 + 50 * gTF.ease_out(0.6), 0.01, "no-0%-no-100% at 1.85s");
advance_clock(100);
is_approx(px_to_num(cs.marginTop), 50 + 50 * gTF.ease_out(0.2), 0.01, "no-0%-no-100% at 1.95s");
advance_clock(50);
is(cs.marginTop, "50px", "no-0%-no-100% at 2.0s");
done_div();
// Test that non-animatable properties are ignored.
// Simultaneously, test that the block is still honored, and that
// we still override the value when two consecutive keyframes have
// the same value.
new_div("animation: kf4 ease 10s");
is(cs.display, "block", "non-animatable properties should be ignored (linear, 0s)");
is(cs.marginTop, "37px", "animatable properties should still apply (linear, 0s)");
advance_clock(1000);
is(cs.display, "block", "non-animatable properties should be ignored (linear, 1s)");
is(cs.marginTop, "37px", "animatable properties should still apply (linear, 1s)");
done_div();
new_div("animation: kf4 step-start 10s");
is(cs.display, "block", "non-animatable properties should be ignored (step-start, 0s)");
is(cs.marginTop, "37px", "animatable properties should still apply (step-start, 0s)");
advance_clock(1000);
is(cs.display, "block", "non-animatable properties should be ignored (step-start, 1s)");
is(cs.marginTop, "37px", "animatable properties should still apply (step-start, 1s)");
done_div();
// Test cascading of the keyframes within an @keyframes rule.
new_div("animation: kf_cascade1 linear 10s");
// 0%: 30px
// 50%: 20px
// 75%: 20px
// 85%: 30px
// 85.1%: 60px
// 100%: 70px
is(cs.paddingTop, "30px", "kf_cascade1 at 0s");
advance_clock(2500);
is(cs.paddingTop, "25px", "kf_cascade1 at 2.5s");
advance_clock(2500);
is(cs.paddingTop, "20px", "kf_cascade1 at 5s");
advance_clock(2000);
is(cs.paddingTop, "20px", "kf_cascade1 at 7s");
advance_clock(500);
is(cs.paddingTop, "20px", "kf_cascade1 at 7.5s");
advance_clock(500);
is(cs.paddingTop, "25px", "kf_cascade1 at 8s");
advance_clock(500);
is(cs.paddingTop, "30px", "kf_cascade1 at 8.5s");
advance_clock(10);
is_approx(px_to_num(cs.paddingTop), 60, 0.001, "kf_cascade1 at 8.51s");
advance_clock(745);
is(cs.paddingTop, "65px", "kf_cascade1 at 9.2505s");
done_div();
// Test cascading of the @keyframes rules themselves.
new_div("animation: kf_cascade2 linear 10s");
is(cs.marginTop, "0px", "@keyframes rule with margin-top should be ignored");
is(cs.marginLeft, "300px", "last @keyframes rule with margin-left should win");
done_div();
/*
* css3-animations: 3.1. Timing functions for keyframes
* http://dev.w3.org/csswg/css3-animations/#timing-functions-for-keyframes-
*/
new_div("animation: kf_tf1 ease-in 10s alternate infinite");
is(cs.paddingBottom, "20px", "keyframe timing functions test at 0s (test needed for flush)");
advance_clock(1000);
is_approx(px_to_num(cs.paddingBottom), 20 + 40 * gTF.ease(0.4), 0.01, "keyframe timing functions test at 1s");
advance_clock(1000);
is_approx(px_to_num(cs.paddingBottom), 20 + 40 * gTF.ease(0.8), 0.01, "keyframe timing functions test at 2s");
advance_clock(1000);
is_approx(px_to_num(cs.paddingBottom), 60 + 100 * gTF.ease_in(0.2), 0.01, "keyframe timing functions test at 3s");
advance_clock(1000);
is_approx(px_to_num(cs.paddingBottom), 60 + 100 * gTF.ease_in(0.6), 0.01, "keyframe timing functions test at 4s");
advance_clock(1000);
is(cs.paddingBottom, "160px", "keyframe timing functions test at 5s");
advance_clock(1001); // avoid floating-point error
is_approx(px_to_num(cs.paddingBottom), 160 - 40 * step_end(5)(0.4), 0.01, "keyframe timing functions test at 6s");
advance_clock(1000);
is_approx(px_to_num(cs.paddingBottom), 160 - 40 * step_end(5)(0.8), 0.01, "keyframe timing functions test at 7s");
advance_clock(999);
is_approx(px_to_num(cs.paddingBottom), 120 - 100 * gTF.linear(0.2), 0.01, "keyframe timing functions test at 8s");
advance_clock(1000);
is_approx(px_to_num(cs.paddingBottom), 120 - 100 * gTF.linear(0.6), 0.01, "keyframe timing functions test at 9s");
advance_clock(1000);
is(cs.paddingBottom, "20px", "keyframe timing functions test at 10s");
advance_clock(20000);
is(cs.paddingBottom, "20px", "keyframe timing functions test at 30s");
advance_clock(1000);
is_approx(px_to_num(cs.paddingBottom), 120 - 100 * gTF.linear(0.6), 0.01, "keyframe timing functions test at 31s");
advance_clock(1000);
is_approx(px_to_num(cs.paddingBottom), 120 - 100 * gTF.linear(0.2), 0.01, "keyframe timing functions test at 32s");
advance_clock(999); // avoid floating-point error
is_approx(px_to_num(cs.paddingBottom), 160 - 40 * step_end(5)(0.8), 0.01, "keyframe timing functions test at 33s");
advance_clock(1000);
is_approx(px_to_num(cs.paddingBottom), 160 - 40 * step_end(5)(0.4), 0.01, "keyframe timing functions test at 34s");
advance_clock(1001);
is(cs.paddingBottom, "160px", "keyframe timing functions test at 35s");
advance_clock(1000);
is_approx(px_to_num(cs.paddingBottom), 60 + 100 * gTF.ease_in(0.6), 0.01, "keyframe timing functions test at 36s");
advance_clock(1000);
is_approx(px_to_num(cs.paddingBottom), 60 + 100 * gTF.ease_in(0.2), 0.01, "keyframe timing functions test at 37s");
advance_clock(1000);
is_approx(px_to_num(cs.paddingBottom), 20 + 40 * gTF.ease(0.8), 0.01, "keyframe timing functions test at 38s");
advance_clock(1000);
is_approx(px_to_num(cs.paddingBottom), 20 + 40 * gTF.ease(0.4), 0.01, "keyframe timing functions test at 39s");
advance_clock(1000);
is(cs.paddingBottom, "20px", "keyframe timing functions test at 40s");
done_div();
// spot-check the same thing without alternate
new_div("animation: kf_tf1 ease-in 10s infinite");
is(cs.paddingBottom, "20px", "keyframe timing functions test at 0s (test needed for flush)");
advance_clock(11000);
is_approx(px_to_num(cs.paddingBottom), 20 + 40 * gTF.ease(0.4), 0.01, "keyframe timing functions test at 11s");
advance_clock(3000);
is_approx(px_to_num(cs.paddingBottom), 60 + 100 * gTF.ease_in(0.6), 0.01, "keyframe timing functions test at 14s");
advance_clock(2001); // avoid floating-point error
is_approx(px_to_num(cs.paddingBottom), 160 - 40 * step_end(5)(0.4), 0.01, "keyframe timing functions test at 16s");
advance_clock(1999);
is_approx(px_to_num(cs.paddingBottom), 120 - 100 * gTF.linear(0.2), 0.01, "keyframe timing functions test at 18s");
done_div();
// animation-name is reasonably well-tested up in the tests for Section
// 2, particularly the tests that "Test that animations continue running
// when the animation name list is changed."
// Test that 'animation-name: none' steps the animation, and setting
// it again starts a new one.
new_div(""); div.style.animation = "anim2 ease-in-out 10s";
is(cs.marginRight, "0px", "after setting animation-name to anim2");
advance_clock(1000);
is_approx(px_to_num(cs.marginRight), 100 * gTF.ease_in_out(0.1), 0.01, "before changing animation-name to none"); div.style.animationName = "none";
is(cs.marginRight, "0px", "after changing animation-name to none");
advance_clock(1000);
is(cs.marginRight, "0px", "after changing animation-name to none plus 1s"); div.style.animationName = "anim2";
is(cs.marginRight, "0px", "after changing animation-name to anim2");
advance_clock(1000);
is_approx(px_to_num(cs.marginRight), 100 * gTF.ease_in_out(0.1), 0.01, "at 1s in animation when animation-name no longer none again"); div.style.animationName = "none";
is(cs.marginRight, "0px", "after changing animation-name to none");
advance_clock(1000);
is(cs.marginRight, "0px", "after changing animation-name to none plus 1s");
done_div();
// FIXME: test animation-duration of 0 (quite a bit, including interaction
// with fill-mode, count, and reversing), once I know what the right
// behavior is.
// simple test with just one animation
new_div(""); div.style.animationTimingFunction = "ease"; div.style.animationName = "anim1"; div.style.animationDuration = "1s"; div.style.animationDirection = "alternate"; div.style.animationIterationCount = "2";
is(cs.marginLeft, "0px", "animation-play-state test 1, at 0s");
advance_clock(250);
is_approx(px_to_num(cs.marginLeft), 80 * gTF.ease(0.5), 0.01, "animation-play-state test 1 at 250ms"); div.style.animationPlayState = "paused";
is_approx(px_to_num(cs.marginLeft), 80 * gTF.ease(0.5), 0.01, "animation-play-state test 1 at 250ms");
advance_clock(250);
is_approx(px_to_num(cs.marginLeft), 80 * gTF.ease(0.5), 0.01, "animation-play-state test 1 still at 500ms"); div.style.animationPlayState = "running";
is_approx(px_to_num(cs.marginLeft), 80 * gTF.ease(0.5), 0.01, "animation-play-state test 1 still at 500ms");
advance_clock(500);
is_approx(px_to_num(cs.marginLeft), 80 + 20 * gTF.ease(0.5), 0.01, "animation-play-state test 1 at 1000ms");
advance_clock(250);
is(cs.marginLeft, "100px", "animation-play-state test 1 at 1250ms");
advance_clock(250);
is_approx(px_to_num(cs.marginLeft), 80 + 20 * gTF.ease(0.5), 0.01, "animation-play-state test 1 at 1500ms"); div.style.animationPlayState = "paused";
is_approx(px_to_num(cs.marginLeft), 80 + 20 * gTF.ease(0.5), 0.01, "animation-play-state test 1 at 1500ms");
advance_clock(2000);
is_approx(px_to_num(cs.marginLeft), 80 + 20 * gTF.ease(0.5), 0.01, "animation-play-state test 1 at 3500ms");
advance_clock(500);
is_approx(px_to_num(cs.marginLeft), 80 + 20 * gTF.ease(0.5), 0.01, "animation-play-state test 1 at 4000ms"); div.style.animationPlayState = "";
is_approx(px_to_num(cs.marginLeft), 80 + 20 * gTF.ease(0.5), 0.01, "animation-play-state test 1 at 4000ms");
advance_clock(500);
is_approx(px_to_num(cs.marginLeft), 80 * gTF.ease(0.5), 0.01, "animation-play-state test 1 at 4500ms");
advance_clock(250);
is(cs.marginLeft, "0px", "animation-play-state test 1, at 4750ms");
advance_clock(250);
is(cs.marginLeft, "0px", "animation-play-state test 1, at 5000ms");
done_div();
// more complicated test with multiple animations (and different directions
// and iteration counts)
new_div(""); div.style.animationTimingFunction = "ease-out, ease-in, ease-in-out"; div.style.animationName = "anim2, anim3, anim4"; div.style.animationDuration = "1s, 2s, 1s"; div.style.animationDirection = "alternate, normal, normal"; div.style.animationIterationCount = "4, 2, infinite";
is(cs.marginRight, "0px", "animation-play-state test 2, at 0s");
is(cs.marginTop, "0px", "animation-play-state test 3, at 0s");
is(cs.marginBottom, "0px", "animation-play-state test 4, at 0s");
advance_clock(250); div.style.animationPlayState = "paused, running"; // pause 1 and 3
is_approx(px_to_num(cs.marginRight), 100 * gTF.ease_out(0.25), 0.01, "animation-play-state test 2 at 250ms");
is_approx(px_to_num(cs.marginTop), 100 * gTF.ease_in(0.125), 0.01, "animation-play-state test 3 at 250ms");
is_approx(px_to_num(cs.marginBottom), 100 * gTF.ease_in_out(0.25), 0.01, "animation-play-state test 4 at 250ms");
advance_clock(250);
is_approx(px_to_num(cs.marginRight), 100 * gTF.ease_out(0.25), 0.01, "animation-play-state test 2 at 500ms");
is_approx(px_to_num(cs.marginTop), 100 * gTF.ease_in(0.25), 0.01, "animation-play-state test 3 at 500ms");
is_approx(px_to_num(cs.marginBottom), 100 * gTF.ease_in_out(0.25), 0.01, "animation-play-state test 4 at 500ms"); div.style.animationPlayState = "paused, running, running"; // unpause 3
is_approx(px_to_num(cs.marginRight), 100 * gTF.ease_out(0.25), 0.01, "animation-play-state test 2 at 500ms");
is_approx(px_to_num(cs.marginTop), 100 * gTF.ease_in(0.25), 0.01, "animation-play-state test 3 at 500ms");
is_approx(px_to_num(cs.marginBottom), 100 * gTF.ease_in_out(0.25), 0.01, "animation-play-state test 4 at 500ms");
advance_clock(250);
is_approx(px_to_num(cs.marginRight), 100 * gTF.ease_out(0.25), 0.01, "animation-play-state test 2 at 750ms");
is_approx(px_to_num(cs.marginTop), 100 * gTF.ease_in(0.375), 0.01, "animation-play-state test 3 at 750ms");
is_approx(px_to_num(cs.marginBottom), 100 * gTF.ease_in_out(0.5), 0.01, "animation-play-state test 4 at 750ms"); div.style.animationPlayState = "running, paused"; // unpause 1, pause 2
advance_clock(0); // notify refresh observers
advance_clock(250);
is_approx(px_to_num(cs.marginRight), 100 * gTF.ease_out(0.5), 0.01, "animation-play-state test 2 at 1000ms");
is_approx(px_to_num(cs.marginTop), 100 * gTF.ease_in(0.375), 0.01, "animation-play-state test 3 at 1000ms");
is_approx(px_to_num(cs.marginBottom), 100 * gTF.ease_in_out(0.75), 0.01, "animation-play-state test 4 at 1000ms"); div.style.animationPlayState = "paused"; // pause all
advance_clock(0); // notify refresh observers
advance_clock(3000);
is_approx(px_to_num(cs.marginRight), 100 * gTF.ease_out(0.5), 0.01, "animation-play-state test 2 at 4000ms");
is_approx(px_to_num(cs.marginTop), 100 * gTF.ease_in(0.375), 0.01, "animation-play-state test 3 at 4000ms");
is_approx(px_to_num(cs.marginBottom), 100 * gTF.ease_in_out(0.75), 0.01, "animation-play-state test 4 at 4000ms"); div.style.animationPlayState = "running, paused"; // pause 2
advance_clock(0); // notify refresh observers
advance_clock(850);
is_approx(px_to_num(cs.marginRight), 100 * gTF.ease_out(0.65), 0.01, "animation-play-state test 2 at 4850ms");
is_approx(px_to_num(cs.marginTop), 100 * gTF.ease_in(0.375), 0.01, "animation-play-state test 3 at 4850ms");
is_approx(px_to_num(cs.marginBottom), 100 * gTF.ease_in_out(0.6), 0.01, "animation-play-state test 4 at 4850ms");
advance_clock(300);
is_approx(px_to_num(cs.marginRight), 100 * gTF.ease_out(0.35), 0.01, "animation-play-state test 2 at 5150ms");
is_approx(px_to_num(cs.marginTop), 100 * gTF.ease_in(0.375), 0.01, "animation-play-state test 3 at 5150ms");
is_approx(px_to_num(cs.marginBottom), 100 * gTF.ease_in_out(0.9), 0.01, "animation-play-state test 4 at 5150ms");
advance_clock(2300);
is_approx(px_to_num(cs.marginRight), 100 * gTF.ease_out(0.05), 0.01, "animation-play-state test 2 at 7450ms");
is_approx(px_to_num(cs.marginTop), 100 * gTF.ease_in(0.375), 0.01, "animation-play-state test 3 at 7450ms");
is_approx(px_to_num(cs.marginBottom), 100 * gTF.ease_in_out(0.2), 0.01, "animation-play-state test 4 at 7450ms");
advance_clock(100);
is(cs.marginRight, "0px", "animation-play-state test 2 at 7550ms");
is_approx(px_to_num(cs.marginTop), 100 * gTF.ease_in(0.375), 0.01, "animation-play-state test 3 at 7550ms");
is_approx(px_to_num(cs.marginBottom), 100 * gTF.ease_in_out(0.3), 0.01, "animation-play-state test 4 at 7550ms"); div.style.animationPlayState = "running"; // unpause 2
advance_clock(0); // notify refresh observers
advance_clock(1000);
is(cs.marginRight, "0px", "animation-play-state test 2 at 7550ms");
is_approx(px_to_num(cs.marginTop), 100 * gTF.ease_in(0.875), 0.01, "animation-play-state test 3 at 7550ms");
is_approx(px_to_num(cs.marginBottom), 100 * gTF.ease_in_out(0.3), 0.01, "animation-play-state test 4 at 7550ms");
advance_clock(500);
is(cs.marginRight, "0px", "animation-play-state test 2 at 8050ms");
is_approx(px_to_num(cs.marginTop), 100 * gTF.ease_in(0.125), 0.01, "animation-play-state test 3 at 8050ms");
is_approx(px_to_num(cs.marginBottom), 100 * gTF.ease_in_out(0.8), 0.01, "animation-play-state test 4 at 8050ms");
advance_clock(1000);
is(cs.marginRight, "0px", "animation-play-state test 2 at 9050ms");
is_approx(px_to_num(cs.marginTop), 100 * gTF.ease_in(0.625), 0.01, "animation-play-state test 3 at 9050ms");
is_approx(px_to_num(cs.marginBottom), 100 * gTF.ease_in_out(0.8), 0.01, "animation-play-state test 4 at 9050ms");
advance_clock(500);
is(cs.marginRight, "0px", "animation-play-state test 2 at 9550ms");
is_approx(px_to_num(cs.marginTop), 100 * gTF.ease_in(0.875), 0.01, "animation-play-state test 3 at 9550ms");
is_approx(px_to_num(cs.marginBottom), 100 * gTF.ease_in_out(0.3), 0.01, "animation-play-state test 4 at 9550ms");
advance_clock(500);
is(cs.marginRight, "0px", "animation-play-state test 2 at 10050ms");
is(cs.marginTop, "0px", "animation-play-state test 3 at 10050ms");
is_approx(px_to_num(cs.marginBottom), 100 * gTF.ease_in_out(0.8), 0.01, "animation-play-state test 4 at 10050ms");
done_div();
// an initially paused animation (bug 1063992)
new_div("animation: anim1 1s paused both");
is(cs.marginLeft, "0px", "animation-play-state test 5, at 0s");
advance_clock(500);
is(cs.marginLeft, "0px", "animation-play-state test 5, at 0.5s"); div.style.animationPlayState = "running";
is(cs.marginLeft, "0px", "animation-play-state test 5, at 0.5s after unpausing");
advance_clock(500);
is(cs.marginLeft, "80px", "animation-play-state test 5, at 1s after unpaused");
done_div();
// test positive delay
new_div("animation: anim2 1s 0.5s ease-out");
is(cs.marginRight, "0px", "positive delay test at 0ms");
advance_clock(400);
is(cs.marginRight, "0px", "positive delay test at 400ms");
advance_clock(100);
is(cs.marginRight, "0px", "positive delay test at 500ms");
advance_clock(100);
is_approx(px_to_num(cs.marginRight), 100 * gTF.ease_out(0.1), 0.01, "positive delay test at 500ms");
done_div();
// test dynamic changes to delay (i.e., that we preserve the start time
// that's before the delay)
new_div("animation: anim2 1s 0.5s ease-out both");
is(cs.marginRight, "0px", "dynamic delay delay test at 0ms");
advance_clock(400);
is(cs.marginRight, "0px", "dynamic delay delay test at 400ms (1)"); div.style.animationDelay = "0.2s";
is_approx(px_to_num(cs.marginRight), 100 * gTF.ease_out(0.2), 0.01, "dynamic delay delay test at 400ms (2)"); div.style.animationDelay = "0.6s";
advance_clock(0);
advance_clock(200);
is(cs.marginRight, "0px", "dynamic delay delay test at 600ms");
advance_clock(200);
is_approx(px_to_num(cs.marginRight), 100 * gTF.ease_out(0.2), 0.01, "dynamic delay delay test at 800ms");
advance_clock(1000);
is(cs.marginRight, "100px", "dynamic delay delay test at 1800ms (1)"); div.style.animationDelay = "1.5s";
is_approx(px_to_num(cs.marginRight), 100 * gTF.ease_out(0.3), 0.01, "dynamic delay delay test at 1800ms (2)"); div.style.animationDelay = "2s";
is(cs.marginRight, "0px", "dynamic delay delay test at 1800ms (3)");
done_div();
// test delay and play-state interaction
new_div("animation: anim2 1s 0.5s ease-out");
is(cs.marginRight, "0px", "delay and play-state delay test at 0ms");
advance_clock(400);
is(cs.marginRight, "0px", "delay and play-state delay test at 400ms"); div.style.animationPlayState = "paused";
advance_clock(0);
advance_clock(100);
is(cs.marginRight, "0px", "delay and play-state delay test at 500ms");
advance_clock(500);
is(cs.marginRight, "0px", "delay and play-state delay test at 1000ms"); div.style.animationPlayState = "running";
advance_clock(0);
advance_clock(100);
is(cs.marginRight, "0px", "delay and play-state delay test at 1100ms");
advance_clock(100);
is_approx(px_to_num(cs.marginRight), 100 * gTF.ease_out(0.1), 0.01, "delay and play-state delay test at 1200ms"); div.style.animationPlayState = "paused";
advance_clock(0);
advance_clock(100);
is_approx(px_to_num(cs.marginRight), 100 * gTF.ease_out(0.1), 0.01, "delay and play-state delay test at 1300ms");
done_div();
// shorthand vs. longhand is adequately tested by the
// property_database.js-based tests.
/**
* Basic tests of animations on pseudo-elements
*/
new_div("");
listen(); div.id = "withbefore"; var cs_before = getComputedStyle(div, ":before");
is(cs_before.marginRight, "0px", ":before test at 0ms");
advance_clock(400);
is(cs_before.marginRight, "40px", ":before test at 400ms");
advance_clock(800);
is(cs_before.marginRight, "80px", ":before test at 1200ms");
is(cs.marginRight, "0px", ":before animation should not affect element");
advance_clock(800);
is(cs_before.marginRight, "0px", ":before test at 2000ms");
advance_clock(300);
is(cs_before.marginRight, "30px", ":before test at 2300ms");
advance_clock(700);
check_events([ { type: "animationstart", animationName: "anim2", elapsedTime: 0, pseudoElement: "::before" },
{ type: "animationiteration", animationName: "anim2", elapsedTime: 1, pseudoElement: "::before" },
{ type: "animationiteration", animationName: "anim2", elapsedTime: 2, pseudoElement: "::before" },
{ type: "animationend", animationName: "anim2", elapsedTime: 3, pseudoElement: "::before" }]);
done_div();
new_div("");
listen(); div.id = "withafter"; var cs_after = getComputedStyle(div, ":after");
is(cs_after.marginRight, "0px", ":after test at 0ms");
advance_clock(400);
is(cs_after.marginRight, "40px", ":after test at 400ms");
advance_clock(800);
is(cs_after.marginRight, "80px", ":after test at 1200ms");
is(cs.marginRight, "0px", ":after animation should not affect element");
advance_clock(800);
is(cs_after.marginRight, "0px", ":after test at 2000ms");
advance_clock(300);
is(cs_after.marginRight, "30px", ":after test at 2300ms");
advance_clock(700);
check_events([ { type: "animationstart", animationName: "anim2", elapsedTime: 0, pseudoElement: "::after" },
{ type: "animationiteration", animationName: "anim2", elapsedTime: 1, pseudoElement: "::after" },
{ type: "animationiteration", animationName: "anim2", elapsedTime: 2, pseudoElement: "::after" },
{ type: "animationend", animationName: "anim2", elapsedTime: 3, pseudoElement: "::after"}]);
done_div();
/**
* Test handling of properties that are present in only some of the
* keyframes.
*/
new_div("animation: multiprop 1s ease-in-out alternate infinite");
is(cs.paddingTop, "10px", "multiprop top at 0ms");
is(cs.paddingLeft, "30px", "multiprop top at 0ms");
advance_clock(100);
is_approx(px_to_num(cs.paddingTop), 10 + 30 * gTF.ease(0.2), 0.01, "multiprop top at 100ms");
is_approx(px_to_num(cs.paddingLeft), 30 + 20 * gTF.ease(0.4), 0.01, "multiprop left at 100ms");
advance_clock(200);
is_approx(px_to_num(cs.paddingTop), 10 + 30 * gTF.ease(0.6), 0.01, "multiprop top at 300ms");
is_approx(px_to_num(cs.paddingLeft), 50 + 10 * gTF.ease_out(0.1), 0.01, "multiprop left at 300ms");
advance_clock(300);
is_approx(px_to_num(cs.paddingTop), 40 + 40 * gTF.ease_in_out(0.4), 0.01, "multiprop top at 600ms");
is_approx(px_to_num(cs.paddingLeft), 50 + 10 * gTF.ease_out(0.7), 0.01, "multiprop left at 600ms");
advance_clock(200);
is_approx(px_to_num(cs.paddingTop), 80 - 80 * gTF.ease_in(0.2), 0.01, "multiprop top at 800ms");
is_approx(px_to_num(cs.paddingLeft), 60 - 60 * gTF.ease_in(0.2), 0.01, "multiprop left at 800ms");
advance_clock(400);
is_approx(px_to_num(cs.paddingTop), 80 - 80 * gTF.ease_in(0.2), 0.01, "multiprop top at 1200ms");
is_approx(px_to_num(cs.paddingLeft), 60 - 60 * gTF.ease_in(0.2), 0.01, "multiprop left at 1200ms");
advance_clock(200);
is_approx(px_to_num(cs.paddingTop), 40 + 40 * gTF.ease_in_out(0.4), 0.01, "multiprop top at 1400ms");
is_approx(px_to_num(cs.paddingLeft), 50 + 10 * gTF.ease_out(0.7), 0.01, "multiprop left at 1400ms");
advance_clock(300);
is_approx(px_to_num(cs.paddingTop), 10 + 30 * gTF.ease(0.6), 0.01, "multiprop top at 1700ms");
is_approx(px_to_num(cs.paddingLeft), 50 + 10 * gTF.ease_out(0.1), 0.01, "multiprop left at 1700ms");
advance_clock(200);
is_approx(px_to_num(cs.paddingTop), 10 + 30 * gTF.ease(0.2), 0.01, "multiprop top at 1900ms");
is_approx(px_to_num(cs.paddingLeft), 30 + 20 * gTF.ease(0.4), 0.01, "multiprop left at 1900ms");
done_div();
// Test for https://bugzilla.mozilla.org/show_bug.cgi?id=651456 -- make
// sure that refreshing of animations doesn't break when we get two
// refreshes with the same timestamp.
new_div("animation: anim2 1s linear");
is(cs.marginRight, "0px", "bug 651456 at 0ms");
advance_clock(100);
is(cs.marginRight, "10px", "bug 651456 at 100ms (1)");
advance_clock(0); // still forces a refresh
is(cs.marginRight, "10px", "bug 651456 at 100ms (2)");
advance_clock(100);
is(cs.marginRight, "20px", "bug 651456 at 200ms");
done_div();
// Test that UA !important rules override animations.
// This test depends on forms.css having a rule
// option { white-space: !important }
// If that rule changes, we should rewrite it to depend on a different rule. varoption;
[ option, cs ] = new_element("option", ""); var default_white_space = cs.whiteSpace;
isnot(default_white_space, "pre", "default style should not be the same as animation style");
done_element();
[ option, cs ] = new_element("option", "animation: uaoverride 2s linear infinite");
is(cs.whiteSpace, default_white_space, "animations should not override UA !important at 0ms");
is(cs.marginTop, "20px", "rest of animation should still work when UA !important present at 0ms");
advance_clock(200);
is(cs.whiteSpace, default_white_space, "animations should not override UA !important at 200ms");
is(cs.marginTop, "40px", "rest of animation should still work when UA !important present at 200ms");
done_element();
// Test that author !important rules override animations, but
// that animations override regular author rules.
new_div("animation: always_fifty 1s linear infinite; margin-left: 200px");
is(cs.marginLeft, "50px", "animations override regular author rules");
done_div();
new_div("animation: always_fifty 1s linear infinite;"
+ " margin-left: 200px ! important;");
is(cs.marginLeft, "200px", "important author rules override animations");
done_div();
// Test interaction of animations and restyling (Bug 686656).
// This test depends on kf3 getting its 0% and 100% values from the
// rules below it in the cascade; we're checking that the animation
// isn't rebuilt when the restyles happen.
new_div("animation: kf3 1s linear forwards");
is(cs.marginTop, "0px", "bug 686656 test 1 at 0ms");
advance_clock(250);
display.style.color = "blue";
is(cs.marginTop, "100px", "bug 686656 test 1 at 250ms");
advance_clock(375);
is(cs.marginTop, "50px", "bug 686656 test 1 at 625ms");
advance_clock(375);
is(cs.marginTop, "0px", "bug 686656 test 1 at 1000ms");
done_div();
display.style.color = "";
// Test interaction of animations and restyling (Bug 686656),
// with reframing.
// This test depends on kf3 getting its 0% and 100% values from the
// rules below it in the cascade; we're checking that the animation
// isn't rebuilt when the restyles happen.
new_div("animation: kf3 1s linear forwards");
is(cs.marginTop, "0px", "bug 686656 test 2 at 0ms");
advance_clock(250);
display.style.overflow = "scroll";
is(cs.marginTop, "100px", "bug 686656 test 2 at 250ms");
advance_clock(375);
is(cs.marginTop, "50px", "bug 686656 test 2 at 625ms");
advance_clock(375);
is(cs.marginTop, "0px", "bug 686656 test 2 at 1000ms");
done_div();
display.style.overflow = "";
// Test that cascading between keyframes rules is per-property rather
// than per-rule (bug ), and that the timing function isn't taken from a
// rule that's skipped. (Bug 738003)
new_div("animation: cascade 1s linear forwards; position: relative");
is(cs.top, "0px", "cascade test (top) at 0ms");
is(cs.left, "0px", "cascade test (top) at 0ms");
advance_clock(125);
is(cs.top, "0px", "cascade test (top) at 125ms");
is(cs.left, "50px", "cascade test (top) at 125ms");
advance_clock(125);
is(cs.top, "0px", "cascade test (top) at 250ms");
is(cs.left, "100px", "cascade test (top) at 250ms");
advance_clock(125);
is(cs.top, "50px", "cascade test (top) at 375ms");
is(cs.left, "100px", "cascade test (top) at 375ms");
advance_clock(125);
is(cs.top, "100px", "cascade test (top) at 500ms");
is(cs.left, "100px", "cascade test (top) at 500ms");
advance_clock(125);
is(cs.top, "100px", "cascade test (top) at 625ms");
is(cs.left, "50px", "cascade test (top) at 625ms");
advance_clock(125);
is(cs.top, "100px", "cascade test (top) at 750ms");
is(cs.left, "0px", "cascade test (top) at 750ms");
advance_clock(125);
is(cs.top, "50px", "cascade test (top) at 875ms");
is(cs.left, "0px", "cascade test (top) at 875ms");
advance_clock(125);
is(cs.top, "0px", "cascade test (top) at 1000ms");
is(cs.left, "0px", "cascade test (top) at 1000ms");
done_div();
new_div("animation: cascade2 8s linear forwards");
is(cs.textIndent, "0px", "cascade2 test at 0s");
advance_clock(1000);
is(cs.textIndent, "25px", "cascade2 test at 1s");
advance_clock(1000);
is(cs.textIndent, "50px", "cascade2 test at 2s");
advance_clock(1000);
is(cs.textIndent, "25px", "cascade2 test at 3s");
advance_clock(1000);
is(cs.textIndent, "0px", "cascade2 test at 4s");
advance_clock(3000);
is(cs.textIndent, "75px", "cascade2 test at 7s");
advance_clock(1000);
is(cs.textIndent, "100px", "cascade2 test at 8s");
done_div();
new_div("animation: primitives1 2s linear forwards");
is(cs.getPropertyValue("transform"), "matrix(1, 0, 0, 1, 0, 0)", "primitives1 at 0s");
advance_clock(1000);
is(cs.getPropertyValue("transform"), "matrix(-0.707107, 0.707107, -0.707107, -0.707107, 0, 0)", "primitives1 at 1s");
advance_clock(1000);
is(cs.getPropertyValue("transform"), "matrix(0, -1, 1, 0, 0, 0)", "primitives1 at 0s");
done_div();
new_div("animation: important1 1s linear forwards");
is(cs.marginTop, "50px", "important1 test at 0s");
advance_clock(500);
is(cs.marginTop, "75px", "important1 test at 0.5s");
advance_clock(500);
is(cs.marginTop, "100px", "important1 test at 1s");
done_div();
new_div("animation: important2 1s linear forwards");
is(cs.marginTop, "50px", "important2 (margin-top) test at 0s");
is(cs.marginBottom, "100px", "important2 (margin-bottom) test at 0s");
advance_clock(1000);
is(cs.marginTop, "0px", "important2 (margin-top) test at 1s");
is(cs.marginBottom, "50px", "important2 (margin-bottom) test at 1s");
done_div();
// Test that it's the length of the 'animation-name' list that's used to
// start animations.
// note: anim2 animates margin-right from 0 to 100px
// note: anim3 animates margin-top from 0 to 100px
new_div("animation-name: anim2, anim3;"
+ " animation-duration: 1s;"
+ " animation-timing-function: linear;"
+ " animation-delay: -250ms, -250ms, -750ms, -500ms;");
is(cs.marginRight, "25px", "animation-name list length is the length that matters");
is(cs.marginTop, "25px", "animation-name list length is the length that matters");
done_div();
new_div("animation-name: anim2, anim3, anim2;"
+ " animation-duration: 1s;"
+ " animation-timing-function: linear;"
+ " animation-delay: -250ms, -250ms, -750ms, -500ms;");
is(cs.marginRight, "75px", "animation-name list length is the length that matters, and the last occurrence of a name wins");
is(cs.marginTop, "25px", "animation-name list length is the length that matters");
done_div();
new_div("margin-right: 200px; animation: anim2 0s 1s both");
listen();
advance_clock(0);
is(cs.getPropertyValue("margin-right"), "0px", "margin-right during backwards fill of zero-duration animation");
advance_clock(2000); // Skip over animation
is(cs.getPropertyValue("margin-right"), "100px", "margin-right during forwards fill of zero-duration animation");
check_events([{ type: 'animationstart', target: div,
animationName: 'anim2', elapsedTime: 0,
pseudoElement: "" },
{ type: 'animationend', target: div,
animationName: 'anim2', elapsedTime: 0,
pseudoElement: "" }], "events after skipping over zero-duration animation");
done_div();
new_div("margin-right: 200px; animation: anim2 0s 1s both");
listen();
advance_clock(0);
// Seek to just before the animation starts and stops
advance_clock(999);
is(cs.getPropertyValue("margin-right"), "0px", "margin-right at exact end of zero-duration animation");
check_events([]);
// Seek to exactly the point where the animation starts and stops
advance_clock(1);
is(cs.getPropertyValue("margin-right"), "100px", "margin-right at exact end of zero-duration animation");
check_events([{ type: 'animationstart', target: div,
animationName: 'anim2', elapsedTime: 0,
pseudoElement: "" },
{ type: 'animationend', target: div,
animationName: 'anim2', elapsedTime: 0,
pseudoElement: "" }], "events after seeking to end of zero-duration animation");
// Check no further events are dispatched
advance_clock(0);
advance_clock(100);
check_events([]);
done_div();
// Test with animation-direction reverse
new_div("margin-right: 200px;"
+ " animation: anim2 0s 1s both reverse");
advance_clock(0);
is(cs.getPropertyValue("margin-right"), "100px", "margin-right during backwards fill of reversed zero-duration animation");
advance_clock(2000);
is(cs.getPropertyValue("margin-right"), "0px", "margin-right during forwards fill of reversed zero-duration animation");
done_div();
// Test with animation-direction alternate
new_div("margin-right: 200px; animation: anim2 0s 1s both alternate 2");
listen();
advance_clock(0);
is(cs.getPropertyValue("margin-right"), "0px", "margin-right during backwards fill of alternating zero-duration animation");
advance_clock(2000);
is(cs.getPropertyValue("margin-right"), "0px", "margin-right during forwards fill of alternating zero-duration animation");
check_events([{ type: 'animationstart', target: div,
animationName: 'anim2', elapsedTime: 0,
pseudoElement: "" },
{ type: 'animationend', target: div,
animationName: 'anim2', elapsedTime: 0,
pseudoElement: "" }], "events after seeking to end of zero-duration animation"
+ " that repeats twice");
done_div();
// Test with animation-direction alternate and odd number of iterations
new_div("margin-right: 200px; animation: anim2 0s 1s both alternate 3");
advance_clock(0);
is(cs.getPropertyValue("margin-right"), "0px", "margin-right during backwards fill of alternating zero-duration " + "animation with odd number of iterations");
advance_clock(2000);
is(cs.getPropertyValue("margin-right"), "100px", "margin-right during forwards fill of alternating zero-duration " + "animation with odd number of iterations");
done_div();
// Test with animation-direction alternate and non-integral number of iterations
new_div("margin-right: 200px;"
+ " animation: anim2 0s 1s both alternate 7.3 linear");
advance_clock(0);
is(cs.getPropertyValue("margin-right"), "0px", "margin-right during backwards fill of alternating zero-duration " + "animation with non-integral number of iterations");
advance_clock(2000);
is(cs.getPropertyValue("margin-right"), "70px", "margin-right during forwards fill of alternating zero-duration " + "animation with non-integral number of iterations");
done_div();
// Test with infinite iteration count
// CSS Animations doesn't actually define what the behavior is in this case
// (and many many other similar cases) so we follow the behavior defined in Web
// Animations which is that the zero-duration "wins".
new_div("margin-right: 200px; animation: anim2 0s 1s both infinite");
listen();
advance_clock(0);
is(cs.getPropertyValue("margin-right"), "0px", "margin-right during backwards fill of infinitely repeating " + "zero-duration animation");
advance_clock(2000);
is(cs.getPropertyValue("margin-right"), "100px", "margin-right during forwards fill of infinitely repeating " + "zero-duration animation");
// Check we don't get infinite iteration events :)
check_events([{ type: 'animationstart', target: div,
animationName: 'anim2', elapsedTime: 0,
pseudoElement: "" },
{ type: 'animationend', target: div,
animationName: 'anim2', elapsedTime: 0,
pseudoElement: "" }], "events after seeking to end of infinitely repeating " + "zero-duration animation");
done_div();
// Test with infinite iteration count and alternating direction
new_div("margin-right: 200px; animation: anim2 0s 1s alternate both infinite");
advance_clock(0);
is(cs.getPropertyValue("margin-right"), "0px", "margin-right during backwards fill of infinitely repeating and " + "alternating zero-duration animation");
advance_clock(2000);
is(cs.getPropertyValue("margin-right"), "0px", "margin-right during forwards fill of infinitely repeating and " + "alternating zero-duration animation");
done_div();
// Test with infinite iteration count and alternate-reverse direction
new_div("margin-right: 200px;"
+ " animation: anim2 0s 1s alternate-reverse infinite both");
advance_clock(0);
is(cs.getPropertyValue("margin-right"), "100px", "margin-right during backwards fill of infinitely repeating and " + "alternate-reverse zero-duration animation");
advance_clock(2000);
is(cs.getPropertyValue("margin-right"), "100px", "margin-right during forwards fill of infinitely repeating and " + "alternate-reverse zero-duration animation");
done_div();
// Test with negative delay
new_div("margin-right: 200px;"
+ " animation: anim2 0s -1s both reverse 12.7 linear");
listen();
cs.animationName; // build animation
advance_clock(0); // finish pending
is(cs.getPropertyValue("margin-right"), "30px", "margin-right during forwards fill of reversed and repeated " + "zero-duration animation with negative delay");
check_events([{ type: 'animationstart', target: div,
animationName: 'anim2', elapsedTime: 0,
pseudoElement: "" },
{ type: 'animationend', target: div,
animationName: 'anim2', elapsedTime: 0,
pseudoElement: "" }], "events after skipping over zero-duration animation " + "with negative delay");
done_div();
// Test zero duration with zero iteration count
new_div("margin-right: 200px; animation: anim2 0s 1s both 0");
listen();
advance_clock(0);
is(cs.getPropertyValue("margin-right"), "0px", "margin-right during backwards fill of zero-duration animation");
advance_clock(2000); // Skip over animation
is(cs.getPropertyValue("margin-right"), "0px", "margin-right during forwards fill of zero-duration animation");
check_events([{ type: 'animationstart', target: div,
animationName: 'anim2', elapsedTime: 0,
pseudoElement: "" },
{ type: 'animationend', target: div,
animationName: 'anim2', elapsedTime: 0,
pseudoElement: "" }], "events after skipping over zero-duration, zero iteration count"
+ " animation");
done_div();
new_div("margin-right: 200px; animation: empty 2s 1s both");
listen();
advance_clock(0);
check_events([], "events during delay");
advance_clock(2000); // Skip to middle of animation div.clientTop; // Trigger events
check_events([{ type: 'animationstart', target: div,
animationName: 'empty', elapsedTime: 0,
pseudoElement: "" }], "middle of animation with empty keyframes rule");
advance_clock(1000); // Skip to end of animation div.clientTop; // Trigger events
check_events([{ type: 'animationend', target: div,
animationName: 'empty', elapsedTime: 2,
pseudoElement: "" }], "end of animation with empty keyframes rule");
done_div();
// Test with a zero-duration animation and empty @keyframes rule
new_div("margin-right: 200px; animation: empty 0s 1s both");
listen();
advance_clock(0);
advance_clock(1000); div.clientTop; // Trigger events
check_events([{ type: 'animationstart', target: div,
animationName: 'empty', elapsedTime: 0,
pseudoElement: "" },
{ type: 'animationend', target: div,
animationName: 'empty', elapsedTime: 0,
pseudoElement: "" }], "end of zero-duration animation with empty keyframes rule");
done_div();
// Test with a keyframes rule that becomes empty
new_div("animation: nearlyempty 1s both linear");
advance_clock(0);
advance_clock(500);
is(cs.getPropertyValue("margin-left"), "50px", "margin-left for animation that is about to be emptied");
listen();
findKeyframesRule("nearlyempty").deleteRule("to");
is(cs.getPropertyValue("margin-left"), "0px", "margin-left for animation with (now) empty keyframes rule");
check_events([], "events after emptying keyframes rule");
advance_clock(500); div.clientTop; // Trigger events
check_events([{ type: 'animationend', target: div,
animationName: 'nearlyempty', elapsedTime: 1,
pseudoElement: "" }], "events at end of animation with newly " + "empty keyframes rule");
done_div();
// Test when we update to point to an empty animation
new_div("animation: always_fifty 1s both linear");
advance_clock(0);
advance_clock(500);
is(cs.getPropertyValue("margin-left"), "50px", "margin-left for animation that will soon point to an empty keyframes rule");
listen(); div.style.animationName = "empty";
is(cs.getPropertyValue("margin-left"), "0px", "margin-left for animation now points to empty keyframes rule");
advance_clock(500); div.clientTop; // Trigger events
check_events([{ type: 'animationstart', target: div,
animationName: 'empty', elapsedTime: 0,
pseudoElement: "" }], "events at start of animation updated to use " + "empty keyframes rule");
done_div();
/*
* Bug 1031319 - 'none' animations
*
* The code under test here is run entirely on the main thread so there is no
* OMTA version of these tests in test_animations_omta.html.
*/
// Setting "animation: none" after animations have finished should not trigger
// animation events
new_div("animation: always_fifty 1s");
listen();
advance_clock(0);
advance_clock(1000);
check_events([{ type: 'animationstart', target: div,
animationName: 'always_fifty', elapsedTime: 0,
pseudoElement: '' },
{ type: 'animationend', target: div,
animationName: 'always_fifty', elapsedTime: 1,
pseudoElement: '' }], "events after running initial animation"); div.style.animation = "none"; div.clientTop; // Trigger events
check_events([], "events after setting animation to 'none'");
done_div();
// Setting "animation: " after animations have finished should not trigger
// animation events
new_div("animation: always_fifty 1s");
listen();
advance_clock(0);
advance_clock(1000);
check_events([{ type: 'animationstart', target: div,
animationName: 'always_fifty', elapsedTime: 0,
pseudoElement: '' },
{ type: 'animationend', target: div,
animationName: 'always_fifty', elapsedTime: 1,
pseudoElement: '' }], "events after running initial animation"); div.style.animation = ""; div.clientTop; // Trigger events
check_events([], "events after setting animation to ''");
done_div();
// Setting "animation: none 1s" should not trigger events
new_div("animation: none 1s");
listen();
advance_clock(0);
advance_clock(1000);
check_events([], "events after setting animation to 'none 1s'");
done_div();
// Setting "animation: 1s" should not trigger events
new_div("animation: 1s");
listen();
advance_clock(0);
advance_clock(1000);
check_events([], "events after setting animation to '1s'");
done_div();
// Setting animation-name: none among other animations should cause only that
// animation to be skipped
new_div("animation-name: always_fifty, none, always_fifty;"
+ " animation-duration: 1s");
listen();
advance_clock(0);
advance_clock(500);
advance_clock(500);
check_events([{ type: 'animationstart', target: div,
animationName: 'always_fifty', elapsedTime: 0,
pseudoElement: '' },
{ type: 'animationstart', target: div,
animationName: 'always_fifty', elapsedTime: 0,
pseudoElement: '' },
{ type: 'animationend', target: div,
animationName: 'always_fifty', elapsedTime: 1,
pseudoElement: '' },
{ type: 'animationend', target: div,
animationName: 'always_fifty', elapsedTime: 1,
pseudoElement: '' }], "events for animation-name: a, none, a");
done_div();
/*
* Bug 1033881 - Non-matching animation-name
*
* The code under test here is run entirely on the main thread so there is no
* OMTA version of these tests in test_animations_omta.html.
*/
/*
* Bug 1140134 - A property in a CSS animation being overridden by later
* animation causes later properties in that animation to be skipped
*/
new_div("position: relative; animation: lowerpriority 1s linear infinite alternate, overridetop 1s linear infinite alternate");
advance_clock(0);
advance_clock(500);
is(cs.getPropertyValue("left"), "50px", "left is animating");
is(cs.getPropertyValue("top"), "0px", "top is not animating");
done_div();
new_div("position: relative; animation: lowerpriority 1s linear infinite alternate, overrideleft 1s linear infinite alternate");
advance_clock(0);
advance_clock(500);
is(cs.getPropertyValue("left"), "0px", "left is not animating");
is(cs.getPropertyValue("top"), "50px", "top is animating");
done_div();
/*
* Bug 962594 - Turn off CSS animations when the element is display:none, or
* is in a display:none subtree.
*/
// Helper function for the two tests below
function testDisplayNoneTurnsOffAnimations(aTestName, aElementToDisplayNone) {
is(cs.getPropertyValue("margin-right"), "0px",
aTestName + "margin-right at 0s");
advance_clock(1000);
is(cs.getPropertyValue("margin-right"), "10px",
aTestName + "margin-right at 1s");
aElementToDisplayNone.style.display = "none";
is(cs.getPropertyValue("margin-right"), "0px",
aTestName + "margin-right after display:none");
advance_clock(1000);
is(cs.getPropertyValue("margin-right"), "0px",
aTestName + "margin-right 1s after display:none");
aElementToDisplayNone.style.display = "";
is(cs.getPropertyValue("margin-right"), "0px",
aTestName + "margin-right after display:block");
advance_clock(1000);
is(cs.getPropertyValue("margin-right"), "10px",
aTestName + "margin-right 1s after display:block");
}
// Check that it works if the animated element itself becomes display:none
new_div("animation: anim2 linear 10s");
testDisplayNoneTurnsOffAnimations("AnimatedElement ", div);
done_div();
// Check that it works if an ancestor of the animated element becomes display:none
new_div("animation: anim2 linear 10s"); var ancestor = document.createElement("div"); div.parentNode.insertBefore(ancestor, div);
ancestor.appendChild(div);
testDisplayNoneTurnsOffAnimations("AncestorElement ", ancestor);
ancestor.parentNode.insertBefore(div, ancestor);
ancestor.remove();
done_div();
/*
* Bug 1125455 - Transitions should not run when animations are running.
*/
new_div("transition: opacity 2s linear; opacity: 0.8");
advance_clock(0);
is(cs.getPropertyValue("opacity"), "0.8", "initial opacity"); div.style.opacity = "0.2";
is(cs.getPropertyValue("opacity"), "0.8", "opacity transition at 0s");
advance_clock(500);
is(cs.getPropertyValue("opacity"), "0.65", "opacity transition at 0.5s"); div.style.animation = "opacitymid 2s linear";
is(cs.getPropertyValue("opacity"), "0.2", "opacity animation overriding transition at 0s");
advance_clock(500);
is(cs.getPropertyValue("opacity"), "0.35", "opacity animation overriding transition at 0.5s");
done_div();
/*
* Bug 1320474 - keyframes-name may be a string, allows names that would otherwise be excluded
*/
new_div("position: relative; animation: \"string name 1\" 1s linear");
advance_clock(0);
is(cs.getPropertyValue("left"), "1px", "animation name as a string"); div.style.animation = "string\\ name\\ 2 1s linear";
is(cs.getPropertyValue("left"), "2px", "animation name specified as string, referenced using custom ident"); div.style.animation = "custom\\ ident\\ 1 1s linear";
is(cs.getPropertyValue("left"), "3px", "animation name specified as custom-ident"); div.style.animation = "\"custom ident 2\" 1s linear";
is(cs.getPropertyValue("left"), "4px", "animation name specified as custom-ident, referenced using string"); div.style.animation = "unset"; div.style.animation = "initial 1s linear";
is(cs.getPropertyValue("left"), "0px", "animation name 'initial' as identifier is ignored"); div.style.animation = "unset"; div.style.animation = "\"initial\" 1s linear";
is(cs.getPropertyValue("left"), "5px", "animation name 'initial' as string is accepted"); div.style.animation = "unset"; div.style.animation = "none 1s linear";
is(cs.getPropertyValue("left"), "0px", "animation name 'none' as identifier is ignored"); div.style.animation = "unset"; div.style.animation = "\"none\" 1s linear";
is(cs.getPropertyValue("left"), "7px", "animation name 'none' as string is accepted");
done_div();
</script>
</pre>
</body>
</html>
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.29 Sekunden
(vorverarbeitet am 2026-04-28)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.