question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Dialog add-padding-to-html technique for scrollbar is problematic and there's no way to control it

See original GitHub issue

Package: @headlessui/react Version: v1.5.0 (latest at time of writing) Chrome + Windows 11 (this issue affects many others as well; see description + case)

Reproduction URL

Any example of the Dialog component is a valid reproduction: open DevTools and monitor the HTML element while opening a Dialog.

Refer to the implementation in dialog.tsx where the issue behaviour is implemented in a useEffect() preceded by the comment line // Scroll lock:

Issue Description

The current Dialog implementation makes less-than-ideal assumptions re scrollbars + project CSS and when a Dialog/modal is open, it applies a technique that adds an inline overflow: hidden and padding-right (with value based on a calculation of scrollbar width) to the document’s <html> tag.

This results in undesired behaviour / jank in different cases especially on Windows PC’s where scrollbars are rather visually imposing.

The lack of control for this behaviour (especially the padding) leaves devs without the ability to more elegantly handle scrollbars and/or handle corner cases or conflicts caused by other styles in a given project.

Why is this important?

Scrollbars are a notoriously fickle beast between different OS’s and browsers (see: one example among many articles on the subject).

I would argue a good reason to check/switch between Mac + PC when working on front-end projects are the differences in scrollbars between these OS’s. Our traffic doesn’t always have the same taste in computers vs. many of us web devs 😄

Example case:

The following breaks down a single case that is part of a wider issue; refer to linked issue + discussion for related cases.

A straightforward cross-platform-friendly technique to avoid jank during loading + transitions that is particularly gross on Windows is to add overflow-y: scroll to the body tag. This causes browsers on PC’s to always display a scrollbar even when the content fits within the viewport (in this case the scrollbar is present but is presented as disabled/inactive).

This technique is in the tailwind-preset.js on several projects I work on and is compatible with many packages/libraries/frameworks to help avoid “jumps” and overall “jank”.

However in this case Dialog is the cause of the very problem it is attempting to prevent:

image

Content behind the Dialog noticeably “jumps” to the left by the width of the scrollbar.

In the screenshot we see padding-right jumping the content by the width of the scrollbar in both of the following cases: when the content is taller than the viewport (i.e. case for y scrollbar), and when it is shorter (i.e. nothing to scroll).

Confirming:

  • when overflow-y: scroll is removed from the body then Dialog behaves the way that the devs presumably intended (tested on Chrome+PC): no padding or jump is present in the content-fits-window case (no scrollbar visible), and in the content-taller-than-window case (scrollbar visible) the added padding compensates for the scrollbar disappearance resulting from Dialog’s addition of overflow: hidden.

The presumably-intended behaviour isn’t particularly elegant in the content-taller-than-window-case on PC either:

Windows’ imposing scrollbar suddenly disappears and this can result in users’ “wtf just blinked”/“jank detection” neurons firing. While a content “jump” is prevented the sudden replacement of the scrollbar with a solid vertical block that doesn’t match the app layout isn’t much better.

At present, devs have no way to control any of this behaviour if they wish to use Dialog –

Before Dialog is rendered (imposing Windows scrollbar is visible):

image

With Dialog modal showing (scrollbar suddenly disappears and it ain’t pretty):

image

Expected/Desired Behaviour

Developers require the ability to control the overflow+padding behaviour of Headless Dialog (e.g. exposed via props)

  • Dialog is making an assumption that depends on other CSS in the project being a certain way that may not always hold true
  • Devs may disagree with an opinionated technique (e.g. jump avoided but jarring swap of scrollbar may not be desired) and wish to override, but still leverage all the other benefits of Headless + Dialog.

Depending on maintainers’ perspective re the presumably-intended behaviour + based on screenshots of it on PC they may wish to classify it as a bug and revisit.

  • Different technique(s) or additional case handling (e.g. scrollbar, PC, etc.) could be implemented to improve Dialog in this area

Related Ideas & Discussions:

Issue Analytics

  • State:closed
  • Created a year ago
  • Reactions:2
  • Comments:10

github_iconTop GitHub Comments

2reactions
amaroychecommented, Nov 16, 2022

Same here, just not having a control over Dialog’s addition of overflow: hidden. This is what is the culprit. Suggesting to solve this and related issues by giving devs a choice to modify this behavior (leaving default as is).

{
    modifyScrollUnderModal: true,
    modifyScrollUnderModalTag: 'html',
    modifyScrollUnderModalStyles: { overflow: 'hidden' }
}
1reaction
missouakcommented, Oct 6, 2022

Package: @headlessui/react Version: v1.5.0 (latest at time of writing) Chrome + Windows 11 (this issue affects many others as well; see description + case)

Reproduction URL

Any example of the Dialog component is a valid reproduction: open DevTools and monitor the HTML element while opening a Dialog.

Refer to the implementation in dialog.tsx where the issue behaviour is implemented in a useEffect() preceded by the comment line // Scroll lock:

Issue Description

The current Dialog implementation makes less-than-ideal assumptions re scrollbars + project CSS and when a Dialog/modal is open, it applies a technique that adds an inline overflow: hidden and padding-right (with value based on a calculation of scrollbar width) to the document’s <html> tag.

This results in undesired behaviour / jank in different cases especially on Windows PC’s where scrollbars are rather visually imposing.

The lack of control for this behaviour (especially the padding) leaves devs without the ability to more elegantly handle scrollbars and/or handle corner cases or conflicts caused by other styles in a given project.

Why is this important?

Scrollbars are a notoriously fickle beast between different OS’s and browsers (see: one example among many articles on the subject).

I would argue a good reason to check/switch between Mac + PC when working on front-end projects are the differences in scrollbars between these OS’s. Our traffic doesn’t always have the same taste in computers vs. many of us web devs 😄

Example case:

The following breaks down a single case that is part of a wider issue; refer to linked issue + discussion for related cases.

A straightforward cross-platform-friendly technique to avoid jank during loading + transitions that is particularly gross on Windows is to add overflow-y: scroll to the body tag. This causes browsers on PC’s to always display a scrollbar even when the content fits within the viewport (in this case the scrollbar is present but is presented as disabled/inactive).

This technique is in the tailwind-preset.js on several projects I work on and is compatible with many packages/libraries/frameworks to help avoid “jumps” and overall “jank”.

However in this case Dialog is the cause of the very problem it is attempting to prevent:

image

Content behind the Dialog noticeably “jumps” to the left by the width of the scrollbar.

In the screenshot we see padding-right jumping the content by the width of the scrollbar in both of the following cases: when the content is taller than the viewport (i.e. case for y scrollbar), and when it is shorter (i.e. nothing to scroll).

Confirming:

  • when overflow-y: scroll is removed from the body then Dialog behaves the way that the devs presumably intended (tested on Chrome+PC): no padding or jump is present in the content-fits-window case (no scrollbar visible), and in the content-taller-than-window case (scrollbar visible) the added padding compensates for the scrollbar disappearance resulting from Dialog’s addition of overflow: hidden.

The presumably-intended behaviour isn’t particularly elegant in the content-taller-than-window-case on PC either:

Windows’ imposing scrollbar suddenly disappears and this can result in users’ “wtf just blinked”/“jank detection” neurons firing. While a content “jump” is prevented the sudden replacement of the scrollbar with a solid vertical block that doesn’t match the app layout isn’t much better.

At present, devs have no way to control any of this behaviour if they wish to use Dialog –

Before Dialog is rendered (imposing Windows scrollbar is visible):

image

With Dialog modal showing (scrollbar suddenly disappears and it ain’t pretty):

image

Expected/Desired Behaviour

Developers require the ability to control the overflow+padding behaviour of Headless Dialog (e.g. exposed via props)

  • Dialog is making an assumption that depends on other CSS in the project being a certain way that may not always hold true
  • Devs may disagree with an opinionated technique (e.g. jump avoided but jarring swap of scrollbar may not be desired) and wish to override, but still leverage all the other benefits of Headless + Dialog.

Depending on maintainers’ perspective re the presumably-intended behaviour + based on screenshots of it on PC they may wish to classify it as a bug and revisit.

  • Different technique(s) or additional case handling (e.g. scrollbar, PC, etc.) could be implemented to improve Dialog in this area

Related Ideas & Discussions:

you can fix it by adding to your main stylesheet file the following : html{ overflow-y: auto!important; }

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to prevent scrollbar from repositioning web page?
I had to use: box-sizing: border-box; // so width will be calculated with padding , padding-right: 1.2rem; // escape scroll-bar width and overflow-x:...
Read more >
scroll-padding - CSS: Cascading Style Sheets - MDN Web Docs
The scroll-padding shorthand property sets scroll padding on all sides of an element at once, much like the padding property does for ...
Read more >
How to Use Scroll Panes - Oracle Help Center
A JScrollPane provides a scrollable view of a component. When screen real estate is limited, use a scroll pane to display a component...
Read more >
Prevent Page Scrolling When a Modal is Open | CSS-Tricks
If we know the top of the scroll location and add it to our CSS, then the body will not scroll back to...
Read more >
Modal - Bootstrap
Use Bootstrap's JavaScript modal plugin to add dialogs to your site for ... Due to how HTML5 defines its semantics, the autofocus HTML...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found