noelboss / featherlight

Featherlight is a very lightweight jQuery lightbox plugin. It's simple yet flexible and easy to use. Featherlight has minimal css and uses no inline styles, everything is name-spaced, it's completely customizable via config object and offers image, ajax and iframe support out of the box. Featherlights small footprint weights about 4kB – in total.
https://www.noevu.ch/featherlight-js-the-ultra-slim-lightbox/
MIT License
2.08k stars 293 forks source link

[feature request] Prevent scrolling on html/body #273

Open corysimmons opened 7 years ago

corysimmons commented 7 years ago

When modals are expanded, it's nice if the html/body isn't able to scroll.

You can achieve this by applying overflow: hidden to both.

Need to be mindful that content can expand vertically further than screen so overflow-y: auto would need to be added to the lightbox container.

marcandre commented 7 years ago

What would be the impact on #77?

corysimmons commented 7 years ago

I don't think the html, body {overflow: hidden} styles would cascade to the <iframe> if it was on a different origin.

I'm too lazy to check if it'd affect it on same origin. If it did, maybe this would work:

html,
body {
  overflow: hidden; // disable for local viewport
}

html html {
  overflow: auto; // enable for child viewport
}

Bootstrap, and 99% of other modal frameworks do this. Locking the viewport is pretty standard with modals.

michaelcoconnor commented 7 years ago

I'm not fully understanding the comments here as I'm not very advanced. That said, I have an example for you of inappropriate scrolling of the underlying page when the user is scrolling in the lightbox. It's on this page. First make sure that your window height is not so huge that scrolling is not necessary to see the bottom of that page. Then, in the sticky footer, click on [Terms of Use].

The deal is that if you keep the cursor inside the Terms of Use box at all times and use the mouse scroll wheel to get to the bottom, all will go well, but... if you keep scrolling a bit more, as if to scroll an inch or more past the end of the box, the underlying page starts to scroll. This also happens in the other direction. In both cases the underlying page must of course not already be scrolled to the end in order for this to be observed.

The comments about overflow don't seem to me to be relevant to what I'm demonstrating, but I'm not utterly sure. Is this a Featherlight bug? Or is it me?

The box is no iframe but is loaded with ordinary HTML, via <a href="#" data-featherlight="url_to_django_script_that_returns_html">.

marcandre commented 7 years ago

After some consideration, I tend to agree with the request.

@corysimmons Is there a need to add overflow: hidden to the body in addition to the <html>?

marcandre commented 7 years ago

Also, the close button should probably not be scrolling. Is there a simple way to achieve that though?

marcandre commented 7 years ago

Latest version should not scroll globally. Would still be nice to have the close box not scrolling either.

michaelcoconnor commented 7 years ago

I have just now installed 1.7.1 on the site to which I provided a link above, and I'm seeing the same scrolling behavior.

jameswilson commented 7 years ago

@marcandre regarding your statement:

Latest version should not scroll globally.

Can you explain what you mean by latest version? I'm still seeing a separate "scroll" branch where this was fixed but never merged to master for inclusion in a release. I just looked at 1.7.7 and it doesn't contain the code from the scroll branch:

https://github.com/noelboss/featherlight/compare/scroll

Were you waiting for a fix of the close box scrolling you mentioned above to work this into a release?

marcandre commented 7 years ago

Oh :blush:, sorry, indeed the changes never made it to master.

1.7.8 released.

jameswilson commented 7 years ago

Mil Merci! @marcandre

jameswilson commented 7 years ago

I've done some cross-browser and device testing of this solution and found that it does not work on iOS, because mobile safari does not respect overflow: hidden on the html element as a way to prevent scrolling. The workaround requires also setting position: fixed on the body tag, and then a small piece of javascript to fix the scroll position in place and prevent that slinky top/bottom edge effect as you drag/scroll with your finger on touch devices.

Here is a workaround that can be used inside my application's script:

  $.featherlight.defaults.beforeOpen = function() {
    // Lock the scroll position in place on the body with 'position:fixed' and negative top margin.
    $(document.body).css({
      'top':  '-' + $(document.body).scrollTop() + 'px',
      'position': 'fixed',
      'width': '100%', // ensure page width unaffected by fixed position.
      'height': 'inherit' // note height of 100% on body breaks ios
    });
  };

  $.featherlight.defaults.afterClose = function() {
    // Unset the scroll position on the body.
    var top = Math.abs(parseInt($(document.body).css('top')));
    $(document.body).css({
      'top': '',  // Empty value removes the CSS rule from the inline style attribute.
      'position': '',
      'width': '',
      'height': ''
    });
    // Move viewport back to the original position which was lost when body was
    // locked with 'position: fixed'.
    window.scrollTo(0, top);
  }

I'll submit a PR momentarily containing this solution rewritten as something that will work generically.

Thanks.

pandalion commented 6 years ago

@marcandre is there any reason not to overwrite the close button position to fixed in our own css? This does the job with the close button for me, to avoid it scrolling out of view.

Edit - I see this wouldnt necessarily work if the modal isn't the size of the window.

ganar commented 6 years ago

@jameswilson thanks a lot for this solution.

If you want the to work across browsers —chrome V 60+ does not work in the original— this small change will do the trick >

'top': '-' + window.scrollY + 'px',

instead of

'top': '-' + $(document.body).scrollTop() + 'px',

I tested the change in Safari, Chrome and Firefox

  $.featherlight.defaults.beforeOpen = function() {
    // Lock the scroll position in place on the body with 'position:fixed' and negative top margin.
    var topOriginal = Math.abs(parseInt($(document.body).css('top')));
    $(document.body).css({
      'top':  '-' + window.scrollY  + 'px',
      'position': 'fixed',
      'width': '100%', // ensure page width unaffected by fixed position.
      'height': 'inherit' // note height of 100% on body breaks ios
    });
  };

  $.featherlight.defaults.afterClose = function() {
    // Unset the scroll position on the body.
    var top = Math.abs(parseInt($(document.body).css('top')));
    $(document.body).css({
      'top': '',  // Empty value removes the CSS rule from the inline style attribute.
      'position': '',
      'width': '',
      'height': ''
    });
    // Move viewport back to the original position which was lost when body was
    // locked with 'position: fixed'.
    window.scrollTo(0, top);
  }