Skip to content

Instantly share code, notes, and snippets.

@vladimirsiljkovic
Last active March 4, 2020 00:05
Show Gist options
  • Save vladimirsiljkovic/9674659f00f730ad8a14689e0115696c to your computer and use it in GitHub Desktop.
Save vladimirsiljkovic/9674659f00f730ad8a14689e0115696c to your computer and use it in GitHub Desktop.
Locking Body Scroll for Modal Overlays in iOS Safari - https://output.jsbin.com/mudutug/

THIS TECHNIQUE IS OBSOLETE AND NO LONGER NECESSARY. THE ISSUE HAS BEEN FIXED IN iOS SAFARI 13 https://bugs.webkit.org/show_bug.cgi?id=153852

Inspired by: https://stackoverflow.com/questions/37713970/ios-css-js-overlay-scroll-but-prevent-body-scroll

This approach switches the roles of main content and overlay content when the overlay is open, making the overlay content behave as the main content and vice versa. Therefore, the overlay will use ≤body≥ as a scrolling container so it will preserve all native functionality when scrolling, opposing to scrolling a div with overflow:auto.

Improvements:

  • Doesn't have an issue when the background content would start srolling instead of the overlay if you reach the end-point of the overlay when scrolling and continue scrolling further.
  • Doesn't show iOS bottom toolbar when opening an overlay, thus not making the page jump. (This toolbar usualy appears only when a user starts scrolling up.)
  • Scrolling down the overlay will show the native iOS toolbars at the top and bottom of a page, and scrolling up will hide them, as if you were scolling the main content.
* {
box-sizing: border-box;
}
body {
margin: 0;
font-size: 21px;
}
.content {
position: relative;
padding: 30px;
}
/* backdrop for overlay */
.content::after {
content: "";
display: none;
position: fixed;
top: -300px; /* for Chrome touchpad bounce */
left: 0;
right: 0;
bottom: -300px; /* for Chrome touchpad bounce */
background: rgba(0,0,0,0.5);
}
#overlay {
align-items: center;
justify-content: center;
border: 2px solid red;
display: none;
padding: 50px;
position: relative;
min-height: 100vh;
}
#overlay-inner {
max-width: 30em;
background: white;
padding: 20px;
box-shadow: 0 0 10px rgba(0,0,0,0.3);
border-radius: 4px;
}
/* OPENED OVERLAY */
body.overlay-open .content {
position:fixed;
left: 0;
right: 0;
}
body.overlay-open .content::after {
display:block;
}
body.overlay-open #overlay {
display: flex;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Locking the Body Scroll for Modal Overlays in iOS Safari</title>
</head>
<body>
<div class="content">
<h1>Locking the Body Scroll for Modal Overlays in iOS Safari</h1>
<button type="button" class="open">Open Modal</button>
<p>Inspired by: <a href="https://stackoverflow.com/questions/37713970/ios-css-js-overlay-scroll-but-prevent-body-scroll">https://stackoverflow.com/questions/37713970/ios-css-js-overlay-scroll-but-prevent-body-scroll</a></p>
<p>This approach switches the roles of main content and overlay content when the overlay is open, making the overlay content behave as the main content and vice versa. Therefore, the overlay will use ≤body≥ as a scrolling container so it will preserve all native functionality when scrolling, opposing to scrolling a div with `overflow:auto`.</p>
<p>Improvements:</p>
<ul>
<li>Doesn't have an issue when the background content would start srolling instead of the overlay if you reach the end-point of the overlay when scrolling and continue scrolling further.</li>
<li>Doesn't show iOS bottom toolbar when opening an overlay, thus not making the page jump. (This toolbar usualy appears only when a user starts scrolling up.)</li>
<li>Scrolling down the overlay will show the native iOS toolbars at the top and bottom of a page, and scrolling up will hide them, as if you were scolling the main content.</li>
</ul>
<button type="button" class="open">Open Modal</button>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt asperiores quas temporibus eligendi, itaque, odit cupiditate? Repellendus blanditiis distinctio ad. Dicta harum quidem, voluptates impedit aspernatur eius modi inventore corrupti.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt asperiores quas temporibus eligendi, itaque, odit cupiditate? Repellendus blanditiis distinctio ad. Dicta harum quidem, voluptates impedit aspernatur eius modi inventore corrupti.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt asperiores quas temporibus eligendi, itaque, odit cupiditate? Repellendus blanditiis distinctio ad. Dicta harum quidem, voluptates impedit aspernatur eius modi inventore corrupti.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt asperiores quas temporibus eligendi, itaque, odit cupiditate? Repellendus blanditiis distinctio ad. Dicta harum quidem, voluptates impedit aspernatur eius modi inventore corrupti.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt asperiores quas temporibus eligendi, itaque, odit cupiditate? Repellendus blanditiis distinctio ad. Dicta harum quidem, voluptates impedit aspernatur eius modi inventore corrupti.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt asperiores quas temporibus eligendi, itaque, odit cupiditate? Repellendus blanditiis distinctio ad. Dicta harum quidem, voluptates impedit aspernatur eius modi inventore corrupti.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt asperiores quas temporibus eligendi, itaque, odit cupiditate? Repellendus blanditiis distinctio ad. Dicta harum quidem, voluptates impedit aspernatur eius modi inventore corrupti.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt asperiores quas temporibus eligendi, itaque, odit cupiditate? Repellendus blanditiis distinctio ad. Dicta harum quidem, voluptates impedit aspernatur eius modi inventore corrupti.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt asperiores quas temporibus eligendi, itaque, odit cupiditate? Repellendus blanditiis distinctio ad. Dicta harum quidem, voluptates impedit aspernatur eius modi inventore corrupti.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt asperiores quas temporibus eligendi, itaque, odit cupiditate? Repellendus blanditiis distinctio ad. Dicta harum quidem, voluptates impedit aspernatur eius modi inventore corrupti.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt asperiores quas temporibus eligendi, itaque, odit cupiditate? Repellendus blanditiis distinctio ad. Dicta harum quidem, voluptates impedit aspernatur eius modi inventore corrupti.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt asperiores quas temporibus eligendi, itaque, odit cupiditate? Repellendus blanditiis distinctio ad. Dicta harum quidem, voluptates impedit aspernatur eius modi inventore corrupti.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt asperiores quas temporibus eligendi, itaque, odit cupiditate? Repellendus blanditiis distinctio ad. Dicta harum quidem, voluptates impedit aspernatur eius modi inventore corrupti.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt asperiores quas temporibus eligendi, itaque, odit cupiditate? Repellendus blanditiis distinctio ad. Dicta harum quidem, voluptates impedit aspernatur eius modi inventore corrupti.</p>
</div>
<div id="overlay">
<div id="overlay-inner">
<button type="button" class="close">Close</button>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt asperiores quas temporibus eligendi, itaque, odit cupiditate? Repellendus blanditiis distinctio ad. Dicta harum quidem, voluptates impedit aspernatur eius modi inventore corrupti.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt asperiores quas temporibus eligendi, itaque, odit cupiditate? Repellendus blanditiis distinctio ad. Dicta harum quidem, voluptates impedit aspernatur eius modi inventore corrupti.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt asperiores quas temporibus eligendi, itaque, odit cupiditate? Repellendus blanditiis distinctio ad. Dicta harum quidem, voluptates impedit aspernatur eius modi inventore corrupti.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt asperiores quas temporibus eligendi, itaque, odit cupiditate? Repellendus blanditiis distinctio ad. Dicta harum quidem, voluptates impedit aspernatur eius modi inventore corrupti.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt asperiores quas temporibus eligendi, itaque, odit cupiditate? Repellendus blanditiis distinctio ad. Dicta harum quidem, voluptates impedit aspernatur eius modi inventore corrupti.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt asperiores quas temporibus eligendi, itaque, odit cupiditate? Repellendus blanditiis distinctio ad. Dicta harum quidem, voluptates impedit aspernatur eius modi inventore corrupti.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt asperiores quas temporibus eligendi, itaque, odit cupiditate? Repellendus blanditiis distinctio ad. Dicta harum quidem, voluptates impedit aspernatur eius modi inventore corrupti.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt asperiores quas temporibus eligendi, itaque, odit cupiditate? Repellendus blanditiis distinctio ad. Dicta harum quidem, voluptates impedit aspernatur eius modi inventore corrupti.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt asperiores quas temporibus eligendi, itaque, odit cupiditate? Repellendus blanditiis distinctio ad. Dicta harum quidem, voluptates impedit aspernatur eius modi inventore corrupti.</p>
<button type="button" class="close">Close</button>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
</body>
</html>
var $content = $('.content');
var scrollTop = null;
$('.open').click(function(e) {
$('body').addClass('overlay-open');
$.lockBody();
});
$('.close').click(function(e) {
$.unlockBody();
$('body').removeClass('overlay-open');
});
$.lockBody = function() {
if(window.pageYOffset) {
scrollTop = window.pageYOffset;
$content.css({
top: - (scrollTop)
});
}
// scroll overlay to top
window.scrollTo(0, 0);
};
$.unlockBody = function() {
$content.css({
top: ''
});
// scroll back to original pos.
window.scrollTo(0, scrollTop);
window.setTimeout(function () {
scrollTop = null;
}, 0);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment