scroll-markers-updated-by-programmatic-scroll.html (4778B)
1 <!DOCTYPE html> 2 <meta charset="utf-8"> 3 <title>CSS Test: scroll tracking for ::scroll-marker </title> 4 <link rel="help" href="https://drafts.csswg.org/css-overflow-5/#scroll-container-scroll"> 5 <script src="/resources/testharness.js"></script> 6 <script src="/resources/testharnessreport.js"></script> 7 <script src="/css/css-transitions/support/helper.js"></script> 8 <script src="/dom/events/scrolling/scroll_support.js"></script> 9 <style> 10 #scroller { 11 overflow: scroll; 12 scroll-marker-group: before; 13 height: 100px; 14 scroll-behavior: smooth; 15 background-color: purple; 16 border: solid 1px black; 17 } 18 19 #scroller::scroll-marker-group { 20 border: 3px solid black; 21 display: flex; 22 width: 100px; 23 height: 20px; 24 } 25 26 #scroller div { 27 width: 100px; 28 height: 100px; 29 } 30 31 #scroller div::scroll-marker { 32 content: ''; 33 background-color: red; 34 display: inline-flex; 35 width: 10px; 36 height: 10px; 37 border-radius: 50%; 38 } 39 40 #scroller div::scroll-marker:target-current { 41 background-color: green; 42 } 43 </style> 44 <div id='scroller'> 45 <div id="initial"></div> 46 <div class="inbetween"></div> 47 <div class="inbetween"></div> 48 <div class="inbetween"></div> 49 <div id='target'></div> 50 </div> 51 <script> 52 const inbetweens = scroller.querySelectorAll(".inbetween"); 53 const GREEN = "rgb(0, 128, 0)"; 54 const RED = "rgb(255, 0, 0)"; 55 56 function assertPseudoElementProperty(originatingElement, pseudoType, backgroundColor) { 57 const pseudoStyle = getComputedStyle(originatingElement, pseudoType); 58 const pseudoBackgroundColor = pseudoStyle.getPropertyValue('background-color'); 59 assert_equals(pseudoBackgroundColor, backgroundColor, pseudoType + 60 " background-color should be " + backgroundColor.toString() + 61 " but was " + pseudoBackgroundColor.toString()); 62 } 63 64 let marker_change_observed = false; 65 function watchFrames() { 66 const initialPseudoStyle = getComputedStyle(initial, "::scroll-marker"); 67 const initialPseudoBackgroundColor = 68 initialPseudoStyle.getPropertyValue('background-color'); 69 70 if (initialPseudoBackgroundColor === RED) { 71 marker_change_observed = true; 72 } else { 73 assert_false(marker_change_observed); 74 assert_equals(initialPseudoBackgroundColor, GREEN, 75 "initial scroll-marker is initially green"); 76 } 77 78 // All the markers in between should always be red. 79 for (const inbetween of inbetweens) { 80 assertPseudoElementProperty(inbetween, "::scroll-marker", RED); 81 } 82 83 // target should become and stay the selected scroll-marker. 84 assertPseudoElementProperty(target, "::scroll-marker", 85 marker_change_observed ? GREEN : RED); 86 87 requestAnimationFrame(watchFrames); 88 } 89 90 function scrollPromise() { 91 return new Promise((resolve) => { 92 // For browsers that don't support the scrollend event, just wait till 93 // at least half the expected scroll is done. 94 if (document.scrollingElement.onscrollend === undefined) { 95 function scrollListener() { 96 const max_scroll_offset = 97 scroller.scrollHeight - scroller.ClientHeight; 98 if (scroller.scrollTop >= max_scroll_offset / 2) { 99 scroller.removeEventListener(scrollListener); 100 resolve(); 101 } 102 } 103 scroller.addEventListener("scroll", scrollListener); 104 } else { 105 function scrollEndListener() { 106 scroller.removeEventListener("scrollend", scrollEndListener); 107 resolve(); 108 } 109 scroller.addEventListener("scrollend", scrollEndListener); 110 } 111 }); 112 }; 113 114 promise_test(async (t) => { 115 await waitForAnimationFrames(2); 116 assertPseudoElementProperty(initial, "::scroll-marker", GREEN); 117 assertPseudoElementProperty(target, "::scroll-marker", RED); 118 119 function changeDivWidths() { 120 const WIDTH1 = "100px"; 121 const WIDTH2 = "200px"; 122 const divs = scroller.querySelectorAll("div"); 123 const current_width = divs[0].style.width; 124 const target_width = current_width === WIDTH1 ? WIDTH2 : WIDTH1; 125 divs.forEach(div => { div.style.width = target_width; }); 126 } 127 128 // Add a scroll listener which will trigger a layout change. 129 // Despite the layout change, the user agent should only select 130 // the eventual scroll position of the ongoing smooth scrollIntoView. 131 scroller.addEventListener("scroll", changeDivWidths); 132 133 const scroll_promise = scrollPromise(); 134 watchFrames(); 135 target.scrollIntoView({ behavior: "smooth" }); 136 await scroll_promise; 137 138 assertPseudoElementProperty(initial, "::scroll-marker", RED); 139 assertPseudoElementProperty(target, "::scroll-marker", GREEN); 140 }, "The selected ::scroll-marker is updated using the eventual scroll " + 141 "position for a programmatic scroll"); 142 </script>