javascript - How to scrollLock body when a modal/lightbox is open -
i using lightbox jquery plugin open lightbox when user clicks on product. lightbox content stretches below fold, , @ moment right scrollbar moves entire page when scroll down.
i'd work pinterest lightbox, whereby right scrollbar scrolls lightbox, , rest of page stays fixed. i've seen few posts on this, nothing seems work me.
problem want lightbox scroll if content bigger viewport of browser not background.
css:
#lightbox{ position: absolute; left: 0; width: 100%; z-index: 100; text-align: center; line-height: 0;} #lightbox img{ width: auto; height: auto;} #lightbox img{ border: none; } #outerimagecontainer{ position: relative; background-color: #fff; width: 250px; height: 250px; margin: 0 auto; } #imagecontainer{ padding: 10px; } #loading{ position: absolute; top: 40%; left: 0%; height: 25%; width: 100%; text-align: center; line-height: 0; } #hovernav{ position: absolute; top: 0; left: 0; height: 100%; width: 100%; z-index: 10; } #imagecontainer>#hovernav{ left: 0;} #hovernav a{ outline: none;} #prevlink, #nextlink{ width: 49%; height: 100%; background-image: url(data:image2/gif;base64,aaaa); /* trick ie showing hover */ display: block; } #prevlink { left: 0; float: left;} #nextlink { right: 0; float: right;} #prevlink:hover, #prevlink:visited:hover { background: url(../images2/prevlabel.gif) left 15% no-repeat; } #nextlink:hover, #nextlink:visited:hover { background: url(../images2/nextlabel.gif) right 15% no-repeat; } #imagedatacontainer{ font: 10px verdana, helvetica, sans-serif; background-color: #fff; margin: 0 auto; line-height: 1.4em; overflow: auto; width: 100% ; } #imagedata{ padding:0 10px; color: #666; } #imagedata #imagedetails{ width: 70%; float: left; text-align: left; } #imagedata #caption{ font-weight: bold; } #imagedata #numberdisplay{ display: block; clear: left; padding-bottom: 1.0em; } #imagedata #bottomnavclose{ width: 66px; float: right; padding-bottom: 0.7em; outline: none;} #overlay{ position: absolute; top: 0; left: 0; z-index: 90; width: 100%; height: 500px; background-color: #000; }
js:
// ----------------------------------------------------------------------------------- // // lightbox v2.04 // lokesh dhakar - http://www.lokeshdhakar.com // last modification: 2/9/08 // // more information, visit: // http://lokeshdhakar.com/projects/lightbox2/ // // licensed under creative commons attribution 2.5 license - http://creativecommons.org/licenses/by/2.5/ // - free use in both personal , commercial projects // - attribution requires leaving author name, author link, , license info intact. // // thanks: scott upton(uptonic.com), peter-paul koch(quirksmode.com), , thomas fuchs(mir.aculo.us) ideas, libs, , snippets. // artemy tregubenko (arty.name) cleanup , in updating latest ver of proto-aculous. // // ----------------------------------------------------------------------------------- /* table of contents ----------------- configuration lightbox class declaration - initialize() - updateimagelist() - start() - changeimage() - resizeimagecontainer() - showimage() - updatedetails() - updatenav() - enablekeyboardnav() - disablekeyboardnav() - keyboardaction() - preloadneighborimages() - end() function calls - document.observe() */ // ----------------------------------------------------------------------------------- // // configurationl // lightboxoptions = object.extend({ fileloadingimage: 'images2/loading.gif', filebottomnavcloseimage: 'images2/closelabel.gif', overlayopacity: 0.8, // controls transparency of shadow overlay animate: true, // toggles resizing animations resizespeed: 7, // controls speed of image resizing animations (1=slowest , 10=fastest) bordersize: 10, //if adjust padding in css, need update variable // when grouping images used write: image # of #. // change non-english localization labelimage: "image", labelof: "of" }, window.lightboxoptions || {}); // ----------------------------------------------------------------------------------- var lightbox = class.create(); lightbox.prototype = { imagearray: [], activeimage: undefined, // initialize() // constructor runs on completion of dom loading. calls updateimagelist , // function inserts html @ bottom of page used display shadow // overlay , image container. // initialize: function() { this.updateimagelist(); this.keyboardaction = this.keyboardaction.bindaseventlistener(this); if (lightboxoptions.resizespeed > 10) lightboxoptions.resizespeed = 10; if (lightboxoptions.resizespeed < 1) lightboxoptions.resizespeed = 1; this.resizeduration = lightboxoptions.animate ? ((11 - lightboxoptions.resizespeed) * 0.15) : 0; this.overlayduration = lightboxoptions.animate ? 0.2 : 0; // shadow fade in/out duration // when lightbox starts resize 250 250 current image dimension. // if animations turned off, hidden prevent flicker of // white 250 250 box. var size = (lightboxoptions.animate ? 250 : 1) + 'px'; // code inserts html @ bottom of page looks similar this: // // <div id="overlay"></div> // <div id="lightbox"> // <div id="outerimagecontainer"> // <div id="imagecontainer"> // <img id="lightboximage"> // <div style="" id="hovernav"> // <a href="#" id="prevlink"></a> // <a href="#" id="nextlink"></a> // </div> // <div id="loading"> // <a href="#" id="loadinglink"> // <img src="images/loading.gif"> // </a> // </div> // </div> // </div> // <div id="imagedatacontainer"> // <div id="imagedata"> // <div id="imagedetails"> // <span id="caption"></span> // <span id="numberdisplay"></span> // </div> // <div id="bottomnav"> // <a href="#" id="bottomnavclose"> // <img src="images/close.gif"> // </a> // </div> // </div> // </div> // </div> var objbody = $$('body')[0]; objbody.appendchild(builder.node('div',{id:'overlay'})); objbody.appendchild(builder.node('div',{id:'lightbox'}, [ builder.node('div',{id:'outerimagecontainer'}, builder.node('div',{id:'imagecontainer'}, [ builder.node('img',{id:'lightboximage'}), builder.node('div',{id:'hovernav'}, [ builder.node('a',{id:'prevlink', href: '#' }), builder.node('a',{id:'nextlink', href: '#' }) ]), builder.node('div',{id:'loading'}, builder.node('a',{id:'loadinglink', href: '#' }, builder.node('img', {src: lightboxoptions.fileloadingimage}) ) ) ]) ), builder.node('div', {id:'imagedatacontainer'}, builder.node('div',{id:'imagedata'}, [ builder.node('div',{id:'imagedetails'}, [ builder.node('span',{id:'caption'}), builder.node('span',{id:'numberdisplay'}) ]), builder.node('div',{id:'bottomnav'}, builder.node('a',{id:'bottomnavclose', href: '#' }, builder.node('img', { src: lightboxoptions.filebottomnavcloseimage }) ) ) ]) ) ])); $('overlay').hide().observe('click', (function() { this.end(); }).bind(this)); $('lightbox').hide().observe('click', (function(event) { if (event.element().id == 'lightbox') this.end(); }).bind(this)); $('outerimagecontainer').setstyle({ width: size, height: size }); $('prevlink').observe('click', (function(event) { event.stop(); this.changeimage(this.activeimage - 1); }).bindaseventlistener(this)); $('nextlink').observe('click', (function(event) { event.stop(); this.changeimage(this.activeimage + 1); }).bindaseventlistener(this)); $('loadinglink').observe('click', (function(event) { event.stop(); this.end(); }).bind(this)); $('bottomnavclose').observe('click', (function(event) { event.stop(); this.end(); }).bind(this)); var th = this; (function(){ var ids = 'overlay lightbox outerimagecontainer imagecontainer lightboximage hovernav prevlink nextlink loading loadinglink ' + 'imagedatacontainer imagedata imagedetails caption numberdisplay bottomnav bottomnavclose'; $w(ids).each(function(id){ th[id] = $(id); }); }).defer(); }, // // updateimagelist() // loops through anchor tags looking 'lightbox' references , applies onclick // events appropriate links. can rerun after dynamically adding images w/ajax. // updateimagelist: function() { this.updateimagelist = prototype.emptyfunction; document.observe('click', (function(event){ var target = event.findelement('a[rel^=lightbox]') || event.findelement('area[rel^=lightbox]'); if (target) { event.stop(); this.start(target); } }).bind(this)); }, // // start() // display overlay , lightbox. if image part of set, add siblings imagearray. // start: function(imagelink) { $$('select', 'object', 'embed').each(function(node){ node.style.visibility = 'hidden' }); // stretch overlay fill page , fade in var arraypagesize = this.getpagesize(); $('overlay').setstyle({ width: arraypagesize[0] + 'px', height: arraypagesize[1] + 'px' }); new effect.appear(this.overlay, { duration: this.overlayduration, from: 0.0, to: lightboxoptions.overlayopacity }); this.imagearray = []; var imagenum = 0; if ((imagelink.rel == 'lightbox')){ // if image not part of set, add single image imagearray this.imagearray.push([imagelink.href, imagelink.title]); } else { // if image part of set.. this.imagearray = $$(imagelink.tagname + '[href][rel="' + imagelink.rel + '"]'). collect(function(anchor){ return [anchor.href, anchor.title]; }). uniq(); while (this.imagearray[imagenum][0] != imagelink.href) { imagenum++; } } // calculate top , left offset lightbox var arraypagescroll = document.viewport.getscrolloffsets(); var lightboxtop = arraypagescroll[1] + (document.viewport.getheight() / 10); var lightboxleft = arraypagescroll[0]; this.lightbox.setstyle({ top: lightboxtop + 'px', left: lightboxleft + 'px' }).show(); this.changeimage(imagenum); }, // // changeimage() // hide elements , preload image in preparation resizing image container. // changeimage: function(imagenum) { this.activeimage = imagenum; // update global var // hide elements during transition if (lightboxoptions.animate) this.loading.show(); this.lightboximage.hide(); this.hovernav.hide(); this.prevlink.hide(); this.nextlink.hide(); // hack: opera9 not support scriptaculous opacity , appear fx this.imagedatacontainer.setstyle({opacity: .0001}); this.numberdisplay.hide(); var imgpreloader = new image(); // once image preloaded, resize image container imgpreloader.onload = (function(){ this.lightboximage.src = this.imagearray[this.activeimage][0]; this.resizeimagecontainer(imgpreloader.width, imgpreloader.height); }).bind(this); imgpreloader.src = this.imagearray[this.activeimage][0]; }, // // resizeimagecontainer() // resizeimagecontainer: function(imgwidth, imgheight) { // current width , height var widthcurrent = this.outerimagecontainer.getwidth(); var heightcurrent = this.outerimagecontainer.getheight(); // new width , height var widthnew = (imgwidth + lightboxoptions.bordersize * 2); var heightnew = (imgheight + lightboxoptions.bordersize * 2); // scalars based on change old new var xscale = (widthnew / widthcurrent) * 100; var yscale = (heightnew / heightcurrent) * 100; // calculate size difference between new , old image, , resize if necessary var wdiff = widthcurrent - widthnew; var hdiff = heightcurrent - heightnew; if (hdiff != 0) new effect.scale(this.outerimagecontainer, yscale, {scalex: false, duration: this.resizeduration, queue: 'front'}); if (wdiff != 0) new effect.scale(this.outerimagecontainer, xscale, {scaley: false, duration: this.resizeduration, delay: this.resizeduration}); // if new , old image same size , no scaling transition necessary, // quick pause prevent image flicker. var timeout = 0; if ((hdiff == 0) && (wdiff == 0)){ timeout = 100; if (prototype.browser.ie) timeout = 250; } (function(){ this.prevlink.setstyle({ height: imgheight + 'px' }); this.nextlink.setstyle({ height: imgheight + 'px' }); this.imagedatacontainer.setstyle({ width: widthnew + 'px' }); this.showimage(); }).bind(this).delay(timeout / 1000); }, // // showimage() // display image , begin preloading neighbors. // showimage: function(){ this.loading.hide(); new effect.appear(this.lightboximage, { duration: this.resizeduration, queue: 'end', afterfinish: (function(){ this.updatedetails(); }).bind(this) }); this.preloadneighborimages(); }, // // updatedetails() // display caption, image number, , bottom nav. // updatedetails: function() { // if caption not null if (this.imagearray[this.activeimage][1] != ""){ this.caption.update(this.imagearray[this.activeimage][1]).show(); } // if image part of set display 'image x of x' if (this.imagearray.length > 1){ this.numberdisplay.update( lightboxoptions.labelimage + ' ' + (this.activeimage + 1) + ' ' + lightboxoptions.labelof + ' ' + this.imagearray.length).show(); } new effect.parallel( [ new effect.slidedown(this.imagedatacontainer, { sync: true, duration: this.resizeduration, from: 0.0, to: 1.0 }), new effect.appear(this.imagedatacontainer, { sync: true, duration: this.resizeduration }) ], { duration: this.resizeduration, afterfinish: (function() { // update overlay size , update nav var arraypagesize = this.getpagesize(); this.overlay.setstyle({ height: arraypagesize[1] + 'px' }); this.updatenav(); }).bind(this) } ); }, // // updatenav() // display appropriate previous , next hover navigation. // updatenav: function() { this.hovernav.show(); // if not first image in set, display prev image button if (this.activeimage > 0) this.prevlink.show(); // if not last image in set, display next image button if (this.activeimage < (this.imagearray.length - 1)) this.nextlink.show(); this.enablekeyboardnav(); }, // // enablekeyboardnav() // enablekeyboardnav: function() { document.observe('keydown', this.keyboardaction); }, // // disablekeyboardnav() // disablekeyboardnav: function() { document.stopobserving('keydown', this.keyboardaction); }, // // keyboardaction() // keyboardaction: function(event) { var keycode = event.keycode; var escapekey; if (event.dom_vk_escape) { // mozilla escapekey = event.dom_vk_escape; } else { // ie escapekey = 27; } var key = string.fromcharcode(keycode).tolowercase(); if (key.match(/x|o|c/) || (keycode == escapekey)){ // close lightbox this.end(); } else if ((key == 'p') || (keycode == 37)){ // display previous image if (this.activeimage != 0){ this.disablekeyboardnav(); this.changeimage(this.activeimage - 1); } } else if ((key == 'n') || (keycode == 39)){ // display next image if (this.activeimage != (this.imagearray.length - 1)){ this.disablekeyboardnav(); this.changeimage(this.activeimage + 1); } } }, // // preloadneighborimages() // preload previous , next images. // preloadneighborimages: function(){ var preloadnextimage, preloadprevimage; if (this.imagearray.length > this.activeimage + 1){ preloadnextimage = new image(); preloadnextimage.src = this.imagearray[this.activeimage + 1][0]; } if (this.activeimage > 0){ preloadprevimage = new image(); preloadprevimage.src = this.imagearray[this.activeimage - 1][0]; } }, // // end() // end: function() { this.disablekeyboardnav(); this.lightbox.hide(); new effect.fade(this.overlay, { duration: this.overlayduration }); $$('select', 'object', 'embed').each(function(node){ node.style.visibility = 'visible' }); }, // // getpagesize() // getpagesize: function() { var xscroll, yscroll; if (window.innerheight && window.scrollmaxy) { xscroll = window.innerwidth + window.scrollmaxx; yscroll = window.innerheight + window.scrollmaxy; } else if (document.body.scrollheight > document.body.offsetheight){ // explorer mac xscroll = document.body.scrollwidth; yscroll = document.body.scrollheight; } else { // explorer mac...would work in explorer 6 strict, mozilla , safari xscroll = document.body.offsetwidth; yscroll = document.body.offsetheight; } var windowwidth, windowheight; if (self.innerheight) { // except explorer if(document.documentelement.clientwidth){ windowwidth = document.documentelement.clientwidth; } else { windowwidth = self.innerwidth; } windowheight = self.innerheight; } else if (document.documentelement && document.documentelement.clientheight) { // explorer 6 strict mode windowwidth = document.documentelement.clientwidth; windowheight = document.documentelement.clientheight; } else if (document.body) { // other explorers windowwidth = document.body.clientwidth; windowheight = document.body.clientheight; } // small pages total height less height of viewport if(yscroll < windowheight){ pageheight = windowheight; } else { pageheight = yscroll; } // small pages total width less width of viewport if(xscroll < windowwidth){ pagewidth = xscroll; } else { pagewidth = windowwidth; } return [pagewidth,pageheight]; } } document.observe('dom:loaded', function () { new lightbox(); });
here's class that'll allow that:
class scrolllock { constructor () { this.pagebody = document.queryselector('body'); this.scrolly = 0; } savescrolly = (num) => { this.scrolly = num; } setscrolly = (num) => { window.scroll(0, num); } setscrolloffset = (voffset) => { this.pagebody.style.top = `-${voffset}px`; } freezebodyscroll = () => { this.savescrolly(window.scrolly); this.setscrolloffset(this.scrolly); this.pagebody.classlist.add('is-fixed'); } unfreezebodyscroll = () => { this.pagebody.classlist.remove('is-fixed'); // don't reset scroll position if lock hasn't occurred if (this.scrolly === 0) return; this.setscrolloffset(0); this.setscrolly(this.scrolly); this.savescrolly(0); } }
include following style declaration:
// in css body.is-fixed { position: fixed; max-width: 100%; }
use:
const { freezebodyscroll, unfreezebodyscroll } = new scrolllock(); // call when open modal freezebodyscroll(); // call when close modal unfreezebodyscroll();
Comments
Post a Comment