keyboard.html (7332B)
1 <!DOCTYPE html> 2 <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-1/#scroll-snap-type" /> 3 <title>Arrow key scroll snapping</title> 4 <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1"> 5 <meta name="flags" content="should"> 6 <meta name="assert" 7 content="Test passes if keyboard scrolling correctly snaps on a snap 8 container"> 9 10 <link rel="stylesheet" href="../support/common.css"> 11 12 <script src="/resources/testharness.js"></script> 13 <script src="/resources/testharnessreport.js"></script> 14 <script src="/resources/testdriver.js"></script> 15 <script src="/resources/testdriver-vendor.js"></script> 16 <script src="/resources/testdriver-actions.js"></script> 17 <script src="/dom/events/scrolling/scroll_support.js"></script> 18 <script src="../support/common.js"></script> 19 20 21 <div id="scroller" tabindex="0"> 22 <div id="space"></div> 23 <div class="snap left top" id="top-left"></div> 24 <div class="snap right top" id="top-right"></div> 25 <div class="snap left bottom" id="bottom-left"></div> 26 </div> 27 28 <script> 29 const scroller = document.getElementById("scroller"); 30 const topLeft = document.getElementById("top-left"); 31 const topRight = document.getElementById("top-right"); 32 33 scrollLeft = () => scroller.scrollLeft; 34 scrollTop = () => scroller.scrollTop; 35 36 function ScrollCounter(test, eventTarget) { 37 this.count = 0; 38 const scrollListener = () => { 39 this.count++; 40 } 41 eventTarget.addEventListener('scroll', scrollListener); 42 test.add_cleanup(() => { 43 eventTarget.removeEventListener('scroll', scrollListener); 44 }); 45 } 46 47 async function initializeScrollPosition(scroller, x, y) { 48 return new Promise(async (resolve) => { 49 if (scroller.scrollLeft != x || scroller.scrollTop != y) { 50 const scrollEndPromise = waitForScrollEndFallbackToDelayWithoutScrollEvent(scroller); 51 scroller.scrollTo(x, y); 52 await scrollEndPromise; 53 } 54 resolve(); 55 }); 56 } 57 58 promise_test(async t => { 59 await initializeScrollPosition(scroller, 0, 0); 60 assert_equals(scroller.scrollTop, 0, "verify test pre-condition"); 61 const scrollCounter = new ScrollCounter(t, scroller); 62 const scrollEndPromise = waitForScrollEndFallbackToDelayWithoutScrollEvent(scroller); 63 await keyPress(scroller, "ArrowDown"); 64 await scrollEndPromise; 65 assert_equals(scroller.scrollTop, 400); 66 // Make sure we don't jump directly to the new snap position. 67 assert_greater_than(scrollCounter.count, 1); 68 }, "Snaps to bottom-left after pressing ArrowDown"); 69 70 promise_test(async t => { 71 await initializeScrollPosition(scroller, 0, 400); 72 assert_equals(scroller.scrollTop, 400, "verify test pre-condition"); 73 const scrollCounter = new ScrollCounter(t, scroller); 74 const scrollEndPromise = waitForScrollEndFallbackToDelayWithoutScrollEvent(scroller); 75 await keyPress(scroller, "ArrowUp"); 76 await scrollEndPromise; 77 assert_equals(scroller.scrollTop, 0); 78 // Make sure we don't jump directly to the new snap position. 79 assert_greater_than(scrollCounter.count, 1); 80 }, "Snaps to top-left after pressing ArrowUp"); 81 82 promise_test(async t => { 83 await initializeScrollPosition(scroller, 0, 0); 84 assert_equals(scroller.scrollTop, 0, "verify test pre-condition"); 85 const scrollCounter = new ScrollCounter(t, scroller); 86 const scrollEndPromise = waitForScrollEndFallbackToDelayWithoutScrollEvent(scroller); 87 await keyPress(scroller, "ArrowRight"); 88 await scrollEndPromise; 89 assert_equals(scroller.scrollLeft, 400); 90 // Make sure we don't jump directly to the new snap position. 91 assert_greater_than(scrollCounter.count, 1); 92 }, "Snaps to top-right after pressing ArrowRight"); 93 94 promise_test(async t => { 95 await initializeScrollPosition(scroller, 400, 0); 96 assert_equals(scroller.scrollLeft, 400, "verify test pre-condition"); 97 const scrollCounter = new ScrollCounter(t, scroller); 98 const scrollEndPromise = waitForScrollEndFallbackToDelayWithoutScrollEvent(scroller); 99 await keyPress(scroller, "ArrowLeft"); 100 await scrollEndPromise; 101 assert_equals(scroller.scrollLeft, 0); 102 // Make sure we don't jump directly to the new snap position. 103 assert_greater_than(scrollCounter.count, 1); 104 }, "Snaps to top-left after pressing ArrowLeft"); 105 106 promise_test(async t => { 107 t.add_cleanup(function() { 108 topLeft.style.width = ""; 109 topRight.style.left = "400px"; 110 }); 111 112 // Make the snap area cover the snapport. 113 topLeft.style.width = "800px"; 114 // Make the distance between the previous and the next snap position larger 115 // than snapport. 116 topRight.style.left = "500px"; 117 await initializeScrollPosition(scroller, 0, 0); 118 assert_equals(scroller.scrollLeft, 0, "verify test pre-condition"); 119 const scrollEndPromise = waitForScrollEndFallbackToDelayWithoutScrollEvent(scroller); 120 await keyPress(scroller, "ArrowRight"); 121 await scrollEndPromise; 122 assert_between_exclusive(scroller.scrollLeft, 0, 500); 123 }, "If the original intended offset is valid as making a snap area cover the" 124 + "snapport, and there's no other snap offset in between, use the original" 125 + "intended offset"); 126 127 promise_test(async t => { 128 t.add_cleanup(function() { 129 topLeft.style.width = ""; 130 topRight.style.left = "400px"; 131 topRight.style.scrollSnapStop = ""; 132 }); 133 134 // Make the snap area cover the snapport. 135 topLeft.style.width = "800px"; 136 // Make the next snap offset closer than the original intended offset. 137 topRight.style.left = "20px"; 138 topRight.style.scrollSnapStop = "always"; 139 await initializeScrollPosition(scroller, 0, 0); 140 assert_equals(scroller.scrollLeft, 0, "verify test pre-condition"); 141 const scrollEndPromise = waitForScrollEndFallbackToDelayWithoutScrollEvent(scroller); 142 await keyPress(scroller, "ArrowRight"); 143 await scrollEndPromise; 144 assert_equals(scroller.scrollLeft, 20); 145 }, "If the original intended offset is valid as making a snap area cover the " 146 + "snapport, but there's a defined snap offset in between, use the defined snap" 147 + " offset."); 148 149 promise_test(async t => { 150 await initializeScrollPosition(scroller, 400, 0); 151 await keyPress(scroller, "ArrowRight"); 152 await waitForDelayWithoutScrollEvent(scroller); 153 assert_equals(scroller.scrollLeft, 400); 154 }, "If there is no valid snap offset on the arrow key's direction other than " 155 + "the current offset, and the scroll-snap-type is mandatory, stay at the " 156 + "current offset."); 157 158 promise_test(async t => { 159 t.add_cleanup(function() { 160 scroller.style.scrollSnapType = "both mandatory"; 161 scroller.style.width = ""; 162 topLeft.style.width = ""; 163 }); 164 165 scroller.style.scrollSnapType = "both proximity"; 166 167 // This test case works only if the scroll amount of pressing "ArrowRight" is 168 // greater than the scroll snap proximity value of the scroll container. 169 // "100px" width of the scroll container works on major browsers. 170 scroller.style.width = "100px"; 171 topLeft.style.width = "80px"; 172 173 await initializeScrollPosition(scroller, 400, 0); 174 assert_equals(scroller.scrollLeft, 400, "verify test pre-condition"); 175 const scrollEndPromise = waitForScrollEndFallbackToDelayWithoutScrollEvent(scroller); 176 await keyPress(scroller, "ArrowRight"); 177 await scrollEndPromise; 178 assert_greater_than(scroller.scrollLeft, 400); 179 }, "If there is no valid snap offset on the arrow key's direction other than " 180 + "the current offset, and the scroll-snap-type is proximity, go to the " 181 + "original intended offset"); 182 </script>