Skip to content

Commit 21cea6f

Browse files
icd2k3stipsan
authored andcommitted
feat: new skipOverflowHiddenElements boolean option (@icd2k3 #225)
1 parent 754cc38 commit 21cea6f

File tree

4 files changed

+35
-7
lines changed

4 files changed

+35
-7
lines changed

README.md

+10
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,16 @@ scrollIntoView(target, {
250250
})
251251
```
252252

253+
#### skipOverflowHiddenElements
254+
255+
Type: `Boolean`<br> Default: `false`
256+
257+
> Introduced in `v2.2.0`
258+
259+
By default the [spec](https://drafts.csswg.org/cssom-view/#scrolling-box) states that `overflow: hidden` elements should be scrollable because it has [been used to allow programatic scrolling](https://drafts.csswg.org/css-overflow-3/#valdef-overflow-hidden). This behavior can sometimes lead to [scrolling issues](https://github.com/stipsan/scroll-into-view-if-needed/pull/225#issue-186419520) when you have a node that is a child of an `overflow: hidden` node.
260+
261+
This package follows the convention [adopted by Firefox](https://hg.mozilla.org/integration/fx-team/rev/c48c3ec05012#l7.18) of setting a boolean option to _not_ scroll all nodes with `overflow: hidden` set.
262+
253263
# TypeScript support
254264

255265
When the library itself is built on TypeScript there's no excuse for not publishing great library definitions!

src/compute.ts

+21-7
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,25 @@ const hasScrollableSpace = (el, axis: 'Y' | 'X') => {
3030

3131
return false
3232
}
33-
const canOverflow = (el, axis: 'Y' | 'X') => {
33+
const canOverflow = (
34+
el,
35+
axis: 'Y' | 'X',
36+
skipOverflowHiddenElements: boolean
37+
) => {
3438
const overflowValue = getComputedStyle(el, null)['overflow' + axis]
3539

40+
if (skipOverflowHiddenElements && overflowValue === 'hidden') {
41+
return false
42+
}
43+
3644
return overflowValue !== 'visible' && overflowValue !== 'clip'
3745
}
3846

39-
const isScrollable = el =>
40-
(hasScrollableSpace(el, 'Y') && canOverflow(el, 'Y')) ||
41-
(hasScrollableSpace(el, 'X') && canOverflow(el, 'X'))
47+
const isScrollable = (el, skipOverflowHiddenElements: boolean) =>
48+
(hasScrollableSpace(el, 'Y') &&
49+
canOverflow(el, 'Y', skipOverflowHiddenElements)) ||
50+
(hasScrollableSpace(el, 'X') &&
51+
canOverflow(el, 'X', skipOverflowHiddenElements))
4252

4353
/**
4454
* Find out which edge to align against when logical scroll position is "nearest"
@@ -67,7 +77,7 @@ const alignNearest = (
6777
* │ │
6878
* ┗━│━━│━┛
6979
* └──┘
70-
*
80+
*
7181
* If element edge C and element edge D are both outside scrolling box edge C and scrolling box edge D
7282
*
7383
* ┏ ━ ━ ━ ━ ┓
@@ -105,7 +115,7 @@ const alignNearest = (
105115
* │ │ └──┘
106116
* │ │
107117
* └──┘
108-
*
118+
*
109119
* If element edge C is outside scrolling box edge C and element width is less than scrolling box width
110120
*
111121
* from to
@@ -191,6 +201,7 @@ export default (
191201
block = 'center',
192202
inline = 'nearest',
193203
boundary,
204+
skipOverflowHiddenElements = false,
194205
} = options
195206
// Allow using a callback to check the boundary
196207
// The default behavior is to check if the current target matches the boundary element or not
@@ -209,7 +220,10 @@ export default (
209220
const frames: Element[] = []
210221
let parent
211222
while (isElement((parent = target.parentNode)) && checkBoundary(target)) {
212-
if (isScrollable(parent) || parent === viewport) {
223+
if (
224+
isScrollable(parent, skipOverflowHiddenElements) ||
225+
parent === viewport
226+
) {
213227
frames.push(parent)
214228
}
215229

src/types.ts

+4
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,16 @@ export type ScrollBehavior = 'auto' | 'instant' | 'smooth'
33
export type ScrollLogicalPosition = 'start' | 'center' | 'end' | 'nearest'
44
// This new option is tracked in this PR, which is the most likely candidate at the time: https://github.com/w3c/csswg-drafts/pull/1805
55
export type ScrollMode = 'always' | 'if-needed'
6+
// New option that skips auto-scrolling all nodes with overflow: hidden set
7+
// See FF implementation: https://hg.mozilla.org/integration/fx-team/rev/c48c3ec05012#l7.18
8+
export type SkipOverflowHiddenElements = boolean
69

710
export interface Options {
811
block?: ScrollLogicalPosition
912
inline?: ScrollLogicalPosition
1013
scrollMode?: ScrollMode
1114
boundary?: CustomScrollBoundary
15+
skipOverflowHiddenElements?: SkipOverflowHiddenElements
1216
}
1317

1418
// Custom behavior, not in any spec

types.js

Whitespace-only changes.

0 commit comments

Comments
 (0)