I’m not able to prevent the main body content from scrolling while a fixed position overlay is showing. Similar questions have been asked many times, but all of the techniques that previously worked do not seem to work on Safari in iOS 10. This seems like a recent issue.
Some notes:
- I can disable scrolling if I set both
html
andbody
tooverflow: hidden
, however that makes the body content scroll to the top. - If the content in the overlay is long enough so that it can be scrolled, scrolling is correctly disabled for the main page content. If the content in the overlay is not long enough to cause scrolling, you can scroll the main page content.
- I included a javascript function from https://blog.christoffer.online/2015-06-10-six-things-i-learnt-about-ios-rubberband-overflow-scrolling/ that disables
touchmove
while the overlay is showing. This worked previously, but no longer works.
Here’s the full HTML source:
<!doctype html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script> <style type="text/css"> html, body { width: 100%; height: 100%; margin: 0; padding: 0; } body { font-family: arial; } #overlay { display: none; position: fixed; z-index: 9999; left: 0; right: 0; top: 0; bottom: 0; overflow: scroll; color: #fff; background: rgba(0, 0, 0, 0.5); } #overlay span { position: absolute; display: block; right: 10px; top: 10px; font-weight: bold; font-size: 44px; cursor: pointer; } #overlay p { display: block; padding: 100px; font-size: 36px; } #page { width: 100%; height: 100%; } a { font-weight: bold; color: blue; } </style> <script> $(function() { $('a').click(function(e) { e.preventDefault(); $('body').css('overflow', 'hidden'); $('#page').addClass('disable-scrolling'); // for touchmove technique below $('#overlay').fadeIn(); }); $('#overlay span').click(function() { $('body').css('overflow', 'auto'); $('#page').removeClass('disable-scrolling'); // for touchmove technique below $('#overlay').fadeOut(); }); }); /* Technique from http://blog.christoffer.me/six-things-i-learnt-about-ios-safaris-rubber-band-scrolling/ */ document.ontouchmove = function ( event ) { var isTouchMoveAllowed = true, target = event.target; while ( target !== null ) { if ( target.classList && target.classList.contains( 'disable-scrolling' ) ) { isTouchMoveAllowed = false; break; } target = target.parentNode; } if ( !isTouchMoveAllowed ) { event.preventDefault(); } }; </script> </head> <body> <div id="overlay"> <span>×</span> <p>fixed popover</p> </div> <div id="page"> <strong>this is the top</strong><br> lots of scrollable content<br> asdfasdf<br> lots of scrollable content<br> asdfasdf<br> lots of scrollable content<br> asdfasdf<br> lots of scrollable content<br> asdfasdf<br> lots of scrollable content<br> asdfasdf<br> lots of scrollable content<br> asdfasdf<br> lots of scrollable content<br> asdfasdf<br> lots of scrollable content<br> asdfasdf<br> lots of scrollable content<br> asdfasdf<br> lots of scrollable content<br> asdfasdf<br> lots of scrollable content<br> asdfasdf<br> lots of scrollable content<br> asdfasdf<br> lots of scrollable content<br> asdfasdf<br> lots of scrollable content<br> asdfasdf<br> lots of scrollable content<br> asdfasdf<br> lots of scrollable content<br> asdfasdf<br> lots of scrollable content<br> asdfasdf<br> lots of scrollable content<br> asdfasdf<br> lots of scrollable content<br> asdfasdf<br> lots of scrollable content<br> asdfasdf<br> <br> <div><a href="#">Show Popover</a></div> <br> <br> </div> </body> </html>
Advertisement
Answer
Add -webkit-overflow-scrolling: touch;
to the #overlay
element.
Then add this JavaScript code at the end of the body tag:
(function () { var _overlay = document.getElementById('overlay'); var _clientY = null; // remember Y position on touch start _overlay.addEventListener('touchstart', function (event) { if (event.targetTouches.length === 1) { // detect single touch _clientY = event.targetTouches[0].clientY; } }, false); _overlay.addEventListener('touchmove', function (event) { if (event.targetTouches.length === 1) { // detect single touch disableRubberBand(event); } }, false); function disableRubberBand(event) { var clientY = event.targetTouches[0].clientY - _clientY; if (_overlay.scrollTop === 0 && clientY > 0) { // element is at the top of its scroll event.preventDefault(); } if (isOverlayTotallyScrolled() && clientY < 0) { //element is at the top of its scroll event.preventDefault(); } } function isOverlayTotallyScrolled() { // https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#Problems_and_solutions return _overlay.scrollHeight - _overlay.scrollTop <= _overlay.clientHeight; } }())