└── README.md /README.md: -------------------------------------------------------------------------------- 1 | ## A `scrollend` Explainer 2 | 3 | Update April 3, 2023: 4 | This is now on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Document/scrollend_event) and shipping in browsers: 5 | - Firefox 109 6 | - Chrome 114 7 | 8 | ### Problem Statement 9 | Web developers often watch scroll events to synchronize ancillary elements, fetch data, trigger animations, and more. Today watching scroll events is done with the [`scroll`](https://developer.mozilla.org/en-US/docs/Web/API/Document/scroll_event) event. But if developers want to know when scroll has ended, or rested and isn't moving anymore, there currently is no event. To work around this, developers set a timeout and/or check scroll positions, to [attempt an estimated scrollend event](https://gomakethings.com/detecting-when-a-visitor-has-stopped-scrolling-with-vanilla-javascript/), like so: 10 | 11 | ```js 12 | element.addEventListener('scroll', () => { 13 | clearTimeout(element.scrollEndTimer); 14 | element.scrollEndTimer = setTimeout(synchronizeFn, 100); 15 | }); 16 | ``` 17 | 18 | The fastest this function can determine when scroll has ended is `100ms`. It's also quite wasteful as it overrides the previous timeout on every scroll tick. Browser engines don't like this waste and developers don't like this delay. Furthermore, this strategy will fire `synchronizeFn()` if a user has scrolled with their finger and paused for 100ms, essentially prematurely firing the event because scroll hasn't changed, but the user isn't done. 19 | 20 | ### Use Cases 21 | 22 | #### #1 Scrollable Tabs 23 | 24 | https://user-images.githubusercontent.com/1134620/206300052-77136c7c-84a4-4ca0-9d13-0b41172c4795.mp4 25 | 26 | https://codepen.io/argyleink/pen/JjXoXVe 27 | 28 | #### #2 Carousel with dots and animation 29 | 30 | https://user-images.githubusercontent.com/1134620/206300625-7164f650-48e6-43bd-873f-42608cf473ba.mp4 31 | 32 | https://codepen.io/argyleink/pen/jOzEpjG/e26504e41694bd6267469ba23effae30 33 | 34 | #### #3 Determining which element has snapped 35 | 36 | https://user-images.githubusercontent.com/1134620/206301175-e18fca95-e05e-45ee-aaf4-b15a6f594fab.mp4 37 | 38 | https://codepen.io/argyleink/pen/wveVPom/17a5b2ee3236403d369881d816b0f03d 39 | 40 | ### Solution 41 | A [`scrollend`](https://drafts.csswg.org/cssom-view/#scrolling-events) event that takes into account user interaction, proper timing, and the visual viewport. 42 | 43 | ```js 44 | element.addEventListener('scrollend', () => { 45 | synchronizeFn() 46 | }); 47 | ``` 48 | --------------------------------------------------------------------------------