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