-
Notifications
You must be signed in to change notification settings - Fork 6.8k
feat(overlay): add a utility for disabling body scroll #1971
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@jelbourn I have a couple of doubts about this:
|
fbbb72a
to
6b4492c
Compare
So this will only work on body. How about making it into directive instead and making it work on any element user adds it to? Shouldn't be too hard, just a couple of changes, maybe a little different method for disabling the scroll as well. |
This may not be an issue for elements, at least the ones that use an overlay. Otherwise it should be simpler since we can block the |
The idea with DisableBodyScroll sounds good for me. |
b2ab61e
to
cf01df8
Compare
cf01df8
to
f4e5585
Compare
@jelbourn can you take a look at https://github.com/angular/material2/pull/1971/files#diff-9e063ef46d4c614a351630e38fff09b9R66 specifically? I'm not too sure how to do the DI in the constructor with the new pattern for the |
@crisbeto Ah, you ran exactly into the same issue I did 😄 You need to do it similar as in a275906#diff-a648493d9ddb16f3470a4d9d93419cffR74 |
Adds a `DisableBodyScroll` injectable that can toggle whether the body is scrollable. Fixes angular#1662.
00aedd9
to
2d82339
Compare
I think this would conflict with other renderers. You should wrap it, but I'm not really sure how it would really help in other renderers, unless they implemented document's and window's methods. Is there any other issue blocking this? |
We don't really need to wrap it, it just won't do anything if the |
Any update on this and when it will be merged? Mainly concerned with dialog right now as it is I am getting the body scrolling happening in the background even though I only want the dialog to be scrollable. |
@alexw10 this is just a utility, different components will use different approaches (if I remember correctly, three were mentioned, blocking, repositioning.. and dunno), but yes, dialog will most likely utilise this. If it ever gets merged. I have serious concerns if something didn't happen to @jelbourn. I hope it's just well deserved holiday. |
@dahaupt Haha yes, I can confirm that nothing bad has happened to Jeremy. He should be able to review this soon. |
@kara Okay fine :) I can sleep better now 😄 |
This PR only sets up the infrastructure that allows for scrolling to be disabled, it doesn't integrate it with any of the components. |
How's the review coming? |
I've been holding off on this one since I'm generally suspicious of the "disable body scroll" concept; I'd like to stick to the philosophy of only modifying the elements that material "owns". However, there could be value in having this as an option for overlays (vs. re-positioning w/ |
Repositioning sucks though. You won't ever manage to make it smooth, especially on phones, tablets and older pcs. I wish it wasn't implemented on tooltip at all #3413 it lags even my new MBP / chrome. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Finally left some comments for discussion. I suspect you'll want to open a fresh PR based on our discussion on the different scroll handling strategies, but we can still talk about how to implement this aspect of it here.
*/ | ||
@Injectable() | ||
export class DisableBodyScroll { | ||
private _bodyStyles: string = ''; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add descriptions for _htmlStyles
and _bodyStyles
since they're not immediately obvious?
* Utilitity that allows for toggling scrolling of the viewport on/off. | ||
*/ | ||
@Injectable() | ||
export class DisableBodyScroll { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about PageScrollBlocker
?
/** | ||
* Disables scrolling if it hasn't been disabled already and if the body is scrollable. | ||
*/ | ||
activate(): void { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How able calling the methods disableScrolling
and enableScrolling
, since I could see someone getting mixed up, e.g., activate
meaning to turn scrolling on.
body.style.position = 'fixed'; | ||
body.style.width = '100%'; | ||
body.style.top = -this._previousScrollPosition + 'px'; | ||
html.style.overflowY = 'scroll'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Always setting overflow: scroll
could be a problem if the page does not already have a visible scrollbar. I think we'd have to be more intelligent about whether or not a scrollbar is already showing. Ultimately we don't want scrollbars appearing when they weren't there before.
Also, there can potentially be a horizontal scrollbar as well.
let html = document.documentElement; | ||
let initialBodyWidth = body.clientWidth; | ||
|
||
this._htmlStyles = html.style.cssText || ''; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than caching the styles and setting them back, what do you think of just adding a removing a CSS class from the body where all of the rules are !important
? It might make things simpler.
// TODO(crisbeto): this avoids issues if the body has a margin, however it prevents the | ||
// body from adapting if the window is resized. check whether it's ok to reset the body | ||
// margin in the core styles. | ||
body.style.maxWidth = initialBodyWidth + 'px'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer if we could avoid getting into the reset styles game. Can you go into more details about what the issue is with the default margin?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It has been a while since I wrote this, but IIRC the margin ended up throwing off some of the measurements.
this._bodyStyles = body.style.cssText || ''; | ||
this._previousScrollPosition = this._viewportRuler.getViewportScrollPosition().top; | ||
|
||
body.style.position = 'fixed'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you about to talk at all about this approach vs. just setting overflow: hidden
to the body?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could do that for the position and the width, but the top
is dynamic. Regarding the overflow: hidden
, I believe that it doesn't work on mobile.
Closing in favor of #4500. |
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
Adds a
DisableBodyScroll
injectable that can toggle whether the body is scrollable.Fixes #1662.