1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
|
<!DOCTYPE html>
<html>
<head>
<link rel="help" src="https://drafts.csswg.org/css-animations-2/#animation-trigger">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/web-animations/testcommon.js"></script>
<script src="/dom/events/scrolling/scroll_support.js"></script>
<script src="support/support.js"></script>
</head>
<body>
<style>
@keyframes myAnim {
from { transform: scaleX(1); }
to { transform: scaleX(5); }
}
.subject, .target {
height: 50px;
width: 50px;
background-color: red;
}
.target {
animation: myAnim linear 0.5s both;
animation-trigger: state;
animation-trigger-range: 150px 200px;
}
.scroll {
animation-trigger-timeline: scroll();
}
.view {
animation-trigger-timeline: view();
}
.deferred {
animation-trigger-timeline: --viewtimeline;
}
.deferred.subject {
view-timeline: --viewtimeline;
}
.scroller {
overflow-y: scroll;
height: 500px;
width: 500px;
border: solid 1px;
position: relative;
}
#wrapper {
timeline-scope: --viewtimeline;
}
#space {
width: 50px;
height: 600px;
}
</style>
<div id="wrapper">
<div id="scroll_scroller" class="scroller">
<div id="space"></div>
<div id="scroll_target" class="scroll subject target" tabindex="0"></div>
<div id="space"></div>
</div>
<div id="view_scroller" class="scroller">
<div id="space"></div>
<div id="view_target" class="view subject target" tabindex="0"></div>
<div id="space"></div>
</div>
<div id="deferred_scroller" class="scroller">
<div id="space"></div>
<div id="deferred_subject" class="deferred subject" tabindex="0"></div>
<div id="space"></div>
</div>
<div id="deferred_target" class="deferred target" tabindex="0"></div>
</div>
<script>
async function testStateAnimationTrigger(test, rangeBoundaries) {
// Just short of the trigger range start, no trigger action expected.
await testAnimationTrigger(test, () => {
return rangeBoundaries.exitTriggerRangeAbove();
}, target, ["animationstart", "animationend"], [false, false]);
// This skips the trigger range and should not play the animation.
await testAnimationTrigger(test, () => {
return rangeBoundaries.exitTriggerRangeBelow();
}, target, ["animationstart", "animationend"], [false, false]);
const initial_transform = getComputedStyle(target).transform;
// This is a state trigger, entering the trigger range plays the
// animation.
await testAnimationTrigger(test, async () => {
// Enter the range.
await rangeBoundaries.enterTriggerRange();
await waitForAnimationFrames(5);
// Expect some progress.
assert_not_equals(getComputedStyle(target).transform,
initial_transform);
// Exit the range, which should pause the animation.
return rangeBoundaries.exitExitRangeBelow();
}, target, ["animationstart", "animationend", "animationcancel"],
[true, false, false]);
let partial_transform = getComputedStyle(target).transform;
// Wait a few frames, then check that the animation is still paused.
await waitForAnimationFrames(5);
assert_equals(getComputedStyle(target).transform, partial_transform);
// This enters the trigger range and should continue the animation.
// Let it play till the end.
await testAnimationTrigger(test, () => {
return rangeBoundaries.enterTriggerRange();
}, target, ["animationstart", "animationend"], [false, true]);
let final_transform = getComputedStyle(target).transform;
// Exit the range. This should have no effect as the animation has
// already finished.
await testAnimationTrigger(test, async () => {
return rangeBoundaries.exitExitRangeAbove();
}, target, ["animationstart", "animationend", "animationcancel"],
[false, false, false]);
// Wait a few frames. Exiting the animation should make no difference;
// the animation is already finished.
await waitForAnimationFrames(5);
assert_equals(getComputedStyle(target).transform, final_transform);
// Enter the range again. This should make no difference. The animation
// is already finished.
await testAnimationTrigger(test, async () => {
return rangeBoundaries.enterTriggerRange();
}, target, ["animationstart", "animationend", "animationcancel"],
[false, false, false]);
// Wait a few frames. Check the animation is still at the end.
await waitForAnimationFrames(5);
assert_equals(getComputedStyle(target).transform, final_transform);
}
// The trigger and exit ranges are the same for this test.
const CSS_TRIGGER_START_PX = 150;
const CSS_TRIGGER_END_PX = 200;
promise_test(async (test) => {
scroller = scroll_scroller;
target = scroll_target;
const rangeBoundaries = getRangeBoundariesForTest(CSS_TRIGGER_START_PX,
CSS_TRIGGER_END_PX,
CSS_TRIGGER_START_PX,
CSS_TRIGGER_END_PX,
scroller);
await testStateAnimationTrigger(test, rangeBoundaries);
}, "once animation triggered via scroll() timeline.");
promise_test(async (test) => {
scroller = view_scroller;
target = view_target;
const COVER_START_OFFSET = 100;
const rangeBoundaries = getRangeBoundariesForTest(
COVER_START_OFFSET + CSS_TRIGGER_START_PX,
COVER_START_OFFSET + CSS_TRIGGER_END_PX,
COVER_START_OFFSET + CSS_TRIGGER_START_PX,
COVER_START_OFFSET + CSS_TRIGGER_END_PX,
scroller);
await testStateAnimationTrigger(test, rangeBoundaries);
}, "once animation triggered via view() timeline.");
promise_test(async (test) => {
scroller = deferred_scroller;
target = deferred_target;
const COVER_START_OFFSET = 100;
const rangeBoundaries = getRangeBoundariesForTest(
COVER_START_OFFSET + CSS_TRIGGER_START_PX,
COVER_START_OFFSET + CSS_TRIGGER_END_PX,
COVER_START_OFFSET + CSS_TRIGGER_START_PX,
COVER_START_OFFSET + CSS_TRIGGER_END_PX,
scroller);
await testStateAnimationTrigger(test, rangeBoundaries);
}, "once animation triggered via deferred (view) timeline.");
</script>
</body>
</html>
|