@@ -235,50 +235,83 @@ export function snapScroll(
235
235
scrollAmount = isPageScroll ? - ( cHeight - bottom ) : - ( cBottom - bottom ) ;
236
236
}
237
237
238
- scrollContainer . scrollBy ( {
239
- left : 0 ,
240
- top : scrollAmount ,
241
- behavior : getScrollBehavior ( ) ,
242
- } ) ;
238
+ let stickyHeight = 0 ;
243
239
244
- // Handle sticky headers
245
240
if ( position === "top" ) {
246
- let stickyFound : boolean ;
247
-
248
- // If we find a sticky element we scroll so that the top of our target
249
- // element coincides with the bottom of the sticky element. We keep doing
250
- // this in case there are stacked sticky elements
251
- do {
252
- stickyFound = false ;
253
- const { x, y, top } = target . element . getBoundingClientRect ( ) ;
254
- const elementsAtCoordinates = document . elementsFromPoint ( x + 5 , y + 5 ) ;
255
-
256
- for ( const element of elementsAtCoordinates ) {
257
- if ( element === target . element || element . contains ( target . element ) ) {
258
- break ;
259
- }
241
+ // Retrieve possible sticky/fixed header height. This handles the cases where
242
+ // the sticky/fixed header was in its final position before scrolling.
243
+ const { x, y } = target . element . getBoundingClientRect ( ) ;
244
+ const elementsAtCoordinates = document . elementsFromPoint (
245
+ x + 5 ,
246
+ y - scrollAmount + 5
247
+ ) ;
260
248
261
- const { position, display, visibility, opacity } =
262
- window . getComputedStyle ( element ) ;
263
-
264
- if (
265
- display !== "none" &&
266
- visibility !== "hidden" &&
267
- opacity !== "0" &&
268
- ( position === "sticky" || position === "fixed" )
269
- ) {
270
- const stickyBottom = element . getBoundingClientRect ( ) . bottom ;
271
- scrollContainer . scrollBy ( {
272
- left : 0 ,
273
- top : top - stickyBottom ,
274
- behavior : getScrollBehavior ( ) ,
275
- } ) ;
276
- stickyFound = true ;
277
- break ;
278
- }
249
+ for ( const element of elementsAtCoordinates ) {
250
+ if ( element === target . element || element . contains ( target . element ) ) {
251
+ break ;
252
+ }
253
+
254
+ const { position, display, visibility, opacity } =
255
+ window . getComputedStyle ( element ) ;
256
+
257
+ if (
258
+ display !== "none" &&
259
+ visibility !== "hidden" &&
260
+ opacity !== "0" &&
261
+ ( position === "sticky" || position === "fixed" )
262
+ ) {
263
+ stickyHeight = element . getBoundingClientRect ( ) . height ;
264
+ break ;
279
265
}
280
- } while ( stickyFound ) ;
266
+ }
267
+
268
+ // Handle the cases where the sticky header wasn't in its final position
269
+ // before scrolling.
270
+ ( scrollContainer === document . documentElement
271
+ ? window
272
+ : scrollContainer
273
+ ) . addEventListener (
274
+ "scrollend" ,
275
+ ( ) => {
276
+ // If we find a sticky element we scroll so that the top of our target
277
+ // element coincides with the bottom of the sticky element. We keep doing
278
+ // this in case there are stacked sticky elements
279
+ const { x, y, top } = target . element . getBoundingClientRect ( ) ;
280
+ const elementsAtCoordinates = document . elementsFromPoint ( x + 5 , y + 5 ) ;
281
+
282
+ for ( const element of elementsAtCoordinates ) {
283
+ if ( element === target . element || element . contains ( target . element ) ) {
284
+ break ;
285
+ }
286
+
287
+ const { position, display, visibility, opacity } =
288
+ window . getComputedStyle ( element ) ;
289
+
290
+ if (
291
+ display !== "none" &&
292
+ visibility !== "hidden" &&
293
+ opacity !== "0" &&
294
+ ( position === "sticky" || position === "fixed" )
295
+ ) {
296
+ const stickyBottom = element . getBoundingClientRect ( ) . bottom ;
297
+ scrollContainer . scrollBy ( {
298
+ left : 0 ,
299
+ top : top - stickyBottom ,
300
+ behavior : getScrollBehavior ( ) ,
301
+ } ) ;
302
+ break ;
303
+ }
304
+ }
305
+ } ,
306
+ { once : true }
307
+ ) ;
281
308
}
309
+
310
+ scrollContainer . scrollBy ( {
311
+ left : 0 ,
312
+ top : scrollAmount - stickyHeight ,
313
+ behavior : getScrollBehavior ( ) ,
314
+ } ) ;
282
315
}
283
316
284
317
export function scroll ( options : ScrollOptions ) {
0 commit comments