Modals¶
Modals are hard to get right, especially cross-browser. Best to use a framework or anything else that gives you a prebuilt component (e.g. Bootstrap). If you need to do something by hand for whatever reason, good luck lol
Dealing with scroll¶
Disable scroll on body and prevent reflowing contents¶
You'll want to disable scrolling in the <body> element when the modal is open and reenable it when the modal is closed. Removing the scrollbar will also cause contents to reflow, since you just removed 9-15px from the right side of the screen. You'll need to compensate for this in the <html> root element and also anything with a fixed position, which might include the top header or navigation and the modal container itself. The width of the scrollbar can vary depending on browser, device, and custom user preferences so best to just calculate it and not assume its width.
javascript:
/*
modal open
*/
// calculate scrollbar width
scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
document.body.style.overflow = 'hidden';
// add padding to <html> and fixed-position header
document.documentElement.style.paddingRight = scrollbarWidth + 'px';
document.querySelector('.header').style.paddingRight = scrollbarWidth + 'px';
/*
modal closed
*/
document.body.style.overflow = 'auto';
// reset padding on <html> and fixed-position header
document.documentElement.style.paddingRight = '0';
document.querySelector('.header').style.paddingRight = '0';
Scroll in modal¶
You'll want the modal to be scrollable if needed. Best to account for this even for small modals, maybe someone turned their phone sideways. Got most of this from: https://stackoverflow.com/a/25874635/10728643
The modal container needs overflow-y: initial !important and the inner modal content needs overflow-y: auto and height needs to be something less than 100% of the viewport height. Height can't be set as %. Setting height: 80vh will make the modal content expand to 80% of the viewport height in all scenarios, which we don't want, so use max-height instead. Also, if you have the modal offset at the top with a margin-top it'll look better to offset by that same amount at the bottom. You can do this easily by using calc():
.modal-wrapper {
overflow-y: initial !important;
}
.modal-content {
margin-top: 0.5rem
overflow-y: auto;
max-height: calc(100vh - 1rem);
}
If you have a transition on your modal, you'll see it shift slightly on the leave transition when the scrollbar in <body> reappears because the .modal-wrapper is fixed position. Bootstrap handles this by waiting until the leave transition is complete before adding the scrollbar back buuut let's jut make it simple since you're already annoyed that you're doing all this work when should be using a prebuilt component in the first place.
Also, chances are you used transform: translateX(-50%) to get your modal centered horizontally, so you'll need to use scrollbarWidth / 2 here. And you'll need to apply this to the left margin, not the left padding.
/*
modal open
*/
...
document.querySelector(.modal-wrapper).style.marginLeft = 0;
/*
modal closed
*/
...
modalAdjust = scrollbarWidth / 2;
document.querySelector(.modal-wrapper).style.marginLeft = modalAdjust + 'px';