scroll-behavior-smooth-positions.html (8484B)
1 <!DOCTYPE html> 2 <title>Testing scroll positions when scrolling an element with smooth behavior</title> 3 <meta name="timeout" content="long"/> 4 <link rel="author" title="Frédéric Wang" href="mailto:fwang@igalia.com"> 5 <link rel="help" href="https://drafts.csswg.org/cssom-view/#propdef-scroll-behavior"> 6 <link rel="help" href="https://drafts.csswg.org/cssom-view/#scrolling-box"> 7 <script src="/resources/testharness.js"></script> 8 <script src="/resources/testharnessreport.js"></script> 9 <script src="/dom/events/scrolling/scroll_support.js"></script> 10 <script src="support/scroll-behavior.js"></script> 11 <style> 12 .scrollable { 13 overflow: auto; 14 width: 400px; 15 height: 200px; 16 scroll-behavior: smooth; 17 } 18 </style> 19 <div id="log"> 20 </div> 21 <div id="overflowNode" class="scrollable"> 22 <div style="width: 2000px; height: 1000px; background: linear-gradient(135deg, red, green);"> 23 <span style="display: inline-block; width: 500px; height: 250px;"></span><span id="elementToReveal" style="display: inline-block; vertical-align: -15px; width: 10px; height: 15px; background: black;"></span> 24 </div> 25 </div> 26 <script> 27 promise_test(async () => { 28 await waitForCompositorReady(); 29 }, "Make sure the page is ready for animation."); 30 31 // For smooth behavior, evolution of scroll positions over time is not specified by CSSOM View. 32 // This test relies on the minimal assumption that scroll position functions are monotonic. 33 ["scroll", "scrollTo", "scrollBy", "scrollIntoView"].forEach(function(scrollFunction) { 34 [{left:0, top:0}, {left:1000, top:0}, {left:0, top:500}, {left:1000, top:500}].forEach((initial) => { 35 var finalLeft = 500; 36 var finalTop = 250; 37 promise_test(() => { 38 return new Promise(function(resolve, reject) { 39 scrollNode(overflowNode, "scroll", "instant", initial.left, initial.top); 40 var oldLeft = overflowNode.scrollLeft; 41 var oldTop = overflowNode.scrollTop; 42 assert_equals(oldLeft, initial.left, "ScrollLeft should be at initial position"); 43 assert_equals(oldTop, initial.top, "ScrollTop should be at initial position"); 44 if (scrollFunction === "scrollBy") 45 scrollNode(overflowNode, scrollFunction, "smooth", finalLeft - initial.left, finalTop - initial.top); 46 else 47 scrollNode(overflowNode, scrollFunction, "smooth", finalLeft, finalTop); 48 observeScrolling(overflowNode, function(done) { 49 try { 50 var newLeft = overflowNode.scrollLeft; 51 var newTop = overflowNode.scrollTop; 52 assert_less_than_equal(Math.hypot(finalLeft - newLeft, finalTop - newTop), Math.hypot(finalLeft - oldLeft, finalTop - oldTop), "Scroll position should move towards the final position"); 53 if (done) { 54 assert_equals(newLeft, finalLeft, "ScrollLeft should reach final position"); 55 assert_equals(newTop, finalTop, "ScrollTop should reach final position"); 56 } 57 oldLeft = newLeft; 58 oldTop = newTop; 59 } catch(e) { 60 reject(e); 61 } 62 if (done) 63 resolve(); 64 }); 65 }); 66 }, `Scroll positions when performing smooth scrolling from (${initial.left}, ${initial.top}) to (${finalLeft}, ${finalTop}) using ${scrollFunction}() `); 67 }); 68 }); 69 70 [{scrollAttribute: "scrollLeft", scrollValue: 500}, {scrollAttribute: "scrollTop", scrollValue: 250}].forEach(function(scrollTest) { 71 var initialPosition = Number(scrollTest.scrollValue) * 2; 72 [0, initialPosition].forEach((initial) => { 73 promise_test(() => { 74 return new Promise(function(resolve, reject) { 75 scrollNode(overflowNode, "scroll", "instant", initial, initial); 76 var oldValue = overflowNode[scrollTest.scrollAttribute]; 77 assert_equals(oldValue, initial, `${scrollTest.scrollAttribute} should be at initial position`); 78 var expectedValue = Number(scrollTest.scrollValue); 79 overflowNode[scrollTest.scrollAttribute] = expectedValue; 80 observeScrolling(overflowNode, function(done) { 81 try { 82 var newValue = overflowNode[scrollTest.scrollAttribute]; 83 assert_less_than_equal(Math.abs(expectedValue - newValue), Math.abs(expectedValue - oldValue), "Scroll position should move towards the final position"); 84 if (done) 85 assert_equals(newValue, expectedValue, `${scrollTest.scrollAttribute} should reach final position`); 86 oldValue = newValue; 87 } catch(e) { 88 reject(e); 89 } 90 if (done) 91 resolve(); 92 }); 93 }); 94 }, `Scroll positions when performing smooth scrolling from ${initial} to ${scrollTest.scrollValue} by setting ${scrollTest.scrollAttribute} `); 95 }); 96 }); 97 98 promise_test(() => { 99 return new Promise(function(resolve, reject) { 100 resetScroll(overflowNode); 101 var initialScrollAborted = false; 102 var scrollDirectionChanged = false; 103 var oldLeft = overflowNode.scrollLeft; 104 var oldTop = overflowNode.scrollTop; 105 assert_equals(oldLeft, 0); 106 assert_equals(oldTop, 0); 107 scrollNode(overflowNode, "scroll", "smooth", 1500, 750); 108 observeScrolling(overflowNode, function(done) { 109 try { 110 var newLeft = overflowNode.scrollLeft; 111 var newTop = overflowNode.scrollTop; 112 if (initialScrollAborted) { 113 if (scrollDirectionChanged) { 114 assert_greater_than_equal(oldLeft, newLeft, "ScrollLeft keeps decreasing"); 115 assert_greater_than_equal(oldTop, newTop, "ScrollTop keeps decreasing"); 116 } else 117 scrollDirectionChanged = newLeft <= oldLeft && newTop <= oldTop; 118 } else { 119 assert_less_than_equal(oldLeft, newLeft, "ScrollLeft keeps increasing"); 120 assert_less_than_equal(oldTop, newTop, "ScrollTop keeps increasing"); 121 if (newLeft > 1000 && newTop > 500) { 122 // Abort the initial scroll. 123 initialScrollAborted = true; 124 scrollNode(overflowNode, "scroll", "smooth", 500, 250); 125 newLeft = overflowNode.scrollLeft; 126 newTop = overflowNode.scrollTop; 127 } 128 } 129 if (done) { 130 assert_equals(newLeft, 500, "ScrollLeft should reach final position"); 131 assert_equals(newTop, 250, "ScrollTop should reach final position"); 132 } 133 oldLeft = newLeft; 134 oldTop = newTop; 135 } catch(e) { 136 reject(e); 137 } 138 if (done) 139 resolve(); 140 }); 141 }); 142 }, "Scroll positions when aborting a smooth scrolling with another smooth scrolling"); 143 144 promise_test(() => { 145 return new Promise(function(resolve, reject) { 146 resetScroll(overflowNode); 147 var initialScrollAborted = false; 148 var oldLeft = overflowNode.scrollLeft; 149 var oldTop = overflowNode.scrollTop; 150 assert_equals(oldLeft, 0); 151 assert_equals(oldTop, 0); 152 scrollNode(overflowNode, "scroll", "smooth", 1500, 750); 153 observeScrolling(overflowNode, function(done) { 154 try { 155 var newLeft = overflowNode.scrollLeft; 156 var newTop = overflowNode.scrollTop; 157 if (!initialScrollAborted) { 158 assert_less_than_equal(oldLeft, newLeft, "ScrollLeft keeps increasing"); 159 assert_less_than_equal(oldTop, newTop, "ScrollTop keeps increasing"); 160 if (newLeft > 1000 && newTop > 500) { 161 // Abort the initial scroll. 162 initialScrollAborted = true; 163 scrollNode(overflowNode, "scroll", "instant", 500, 250); 164 newLeft = overflowNode.scrollLeft; 165 newTop = overflowNode.scrollTop; 166 assert_equals(newLeft, 500, "ScrollLeft should reach final position"); 167 assert_equals(newTop, 250, "ScrollTop should reach final position"); 168 } 169 } 170 if (done) { 171 assert_equals(newLeft, 500, "ScrollLeft should stay at final position"); 172 assert_equals(newTop, 250, "ScrollTop should stay at final position"); 173 } 174 oldLeft = newLeft; 175 oldTop = newTop; 176 } catch(e) { 177 reject(e); 178 } 179 if (done) 180 resolve(); 181 }); 182 }); 183 }, "Scroll positions when aborting a smooth scrolling with an instant scrolling"); 184 </script>