A ‘document overlay’ is usually used to focus a user’s attention on a modal window and/or to make it impossible for them to use/navigate the document; something which you’d want to do if a form is processing or if you need the user to wait for something.
The easiest way to block user interaction with a page is to make a new element and stretch it over the top of all other elements thus disabling them (from the user’s point of view). It’ll usually be an absolutely positioned element with a very high z-index. Browser inconsistencies can make it tricky but overall it’s a simple and useful method of blocking user interaction.
new: documentOverlay
Since I’ve found myself having to use one of these overlays quite frequently I’ve decided to create a very reusable, entirely independent and cross-browser compatible solution.
I’m currently experimenting with a slightly different design pattern (A more object-orientated approach), which I hope I’ve done correctly… Before looking at the source it’s best to see what type of thing I’m talking about: (Click below)
Click here for a demo
Note: (Double click the overlay to remove it)
The source:
DOWNLOAD FILE (~3k)
The file and the preview below will remain updated with the latest version.
function documentOverlay() { // @version 0.12 // @author James Padolsey // @info https://j11y.io/javascript/the-perfect-document-overlay/ // Shortcut to current instance of object: var instance = this, // Cached body height: bodyHeight = (function(){ return getDocDim('Height','min'); })(); // CSS helper function: function css(el,o) { for (var i in o) { el.style[i] = o[i]; } return el; }; // Document height/width getter: function getDocDim(prop,m){ m = m || 'max'; return Math[m]( Math[m](document.body["scroll" + prop], document.documentElement["scroll" + prop]), Math[m](document.body["offset" + prop], document.documentElement["offset" + prop]), Math[m](document.body["client" + prop], document.documentElement["client" + prop]) ); } // get window height: (viewport): function getWinHeight() { return window.innerHeight || (document.compatMode == "CSS1Compat" && document.documentElement.clientHeight || document.body.clientHeight); } // Public properties: // Expose CSS helper, for public usage: this.css = function(o){ css(instance.element, o); return instance; }; // The default duration is infinity: this.duration = null; // Creates and styles new div element: this.element = (function(){ return css(document.createElement('div'),{ width: '100%', height: getDocDim('Height') + 'px', position: 'absolute', zIndex: 999, left: 0, top: 0, cursor: 'wait' }); })(); // Resize cover when window is resized: window.onresize = function(){ // No need to do anything if document['body'] is taller than viewport if(bodyHeight>getWinHeight()) { return; } // We need to hide it before showing // it again, due to scrollbar issue. instance.css({display: 'none'}); setTimeout(function(){ instance.css({ height: getDocDim('Height') + 'px', display: 'block' }); }, 10); }; // Remove the element: this.remove = function(){ this.element.parentNode && this.element.parentNode.removeChild(instance.element); }; // Show element: this.show = function(){}; // Event handling helper: this.on = function(what,handler){ what.toLowerCase() === 'show' ? (instance.show = handler) : instance.element['on'+what] = handler; return instance; }; // Begin: this.init = function(duration){ // Overwrite duration if parameter is supplied: instance.duration = duration || instance.duration; // Inject overlay element into DOM: document.getElementsByTagName('body')[0].appendChild(instance.element); // Run show() (by default, an empty function): instance.show.call(instance.element,instance); // If a duration is supplied then remove element after // the specified amount of time: instance.duration && setTimeout(function(){instance.remove();}, instance.duration); // Return instance, for reference: return instance; }; } |
Usage/Examples:
Instantiating the documentOverlay
can either be a very simple call or a highly customizable one:
#1 Basic, uses defaults:
// (make it last for 3 seconds) var myOverlay = new documentOverlay(); myOverlay.duration = 3000; myOverlay.init(); |
#2 Customize CSS of overlay:
var myOverlay = new documentOverlay(); myOverlay.css({ background: 'black', opacity: 0.5, filter: 'alpha(opacity=50)' }).init(); // -------------------------------------- // Yes, it does support basic chaining!!! // -------------------------------------- |
#3 Customize CSS and add an event:
var myOverlay = (new documentOverlay()) .css({ background: 'black', opacity: 0.5, filter: 'alpha(opacity=50)' }) .on('click',function(){ myOverlay.remove(); }) .init(); |
#4 Basic setup – remove when Esc key is pressed:
var myOverlay = (new documentOverlay()).init(); document.onkeyup = function(event){ var keycode = window.event ? window.event.keyCode : event.which; // 27 === Esc. keycode if (keycode == 27) { myOverlay.remove(); } } |
#5 Fade-in the overlay:
// (Make it last for 10 seconds) (new documentOverlay()) .css({ background: 'black', // Set opacity to ZERO! opacity: 0, filter: 'alpha(opacity=0)' }) .on('show', function(){ // Let's use jQuery! $(this).animate({ opacity: 0.5 }); }) .init(10000); // < you can set the duration right here! |
My main objective was to give maximum control to whoever uses this. As you can see from above it’s very easy to customize and it doesn’t require much polluting of the global (or any) namespace because it’s *mostly* encapsulated within itself. Because it allows chaining there’s no need to create any variables or containers. If you don’t like the idea of chaining then you can use a design pattern to which you’re accustomed; a classical example:
(function(){ var myOverlay = new documentOverlay(), overlayElement = myOverlay.element; overlayElement.style.background = 'red'; overlayElement.ondblclick = function(){ alert('This is about to close!'); myOverlay.remove(); } myOverlay.init(); })(); |
Defaults
By default (if you don’t add any custom events/css) the overlay will have no background colour so will be totally invisible to the user. The cursor on the overlay is set to the ‘wait’ symbol – this is easily changeable using the css()
method.
There is no default duration so the overlay will remain indefinitely. To remove it after an amount of time you can pass a millisecond parameter to the init()
method, or you can access it directly as a public property of the constructor. In order to remove the overlay "manually" you’ll need to keep a reference to the actual DOM node (accessible through (new documentOverlay()).element
) or you can use the remove()
method as shown in examples #3 and #4 above.
Last words
I realize that this may be a bit too much for most people – I mean, it’s 3k and all it does it show an overlay, boring! But I hope someone finds it useful! 🙂
Thanks for reading! Please share your thoughts with me on Twitter. Have a great day!
At which point I would add for example a text message and how?
Do you mean a message within some type of modal window? It’s just a case of adding another element which sits above the overlay. There are some cool jQuery plugins too – look at this: http://abeautifulsite.net/notebook_files/87/demo/
Perfect. Thanks.
Really nice. Thank you.
Awsome overlay! This will work perfectly with my new project. Thanks 🙂
This is simply amazing. The link you provided to Karimun is also really helpful. I’m not that great with javascript but I’m starting to learn more and more. I’m definitely going to have to try this out. I love your website by the way.
Unfortunately the overlay doesn’t address the problem of drop downs having an infinite z-index in ie 6? A common work-around for this is to hide them on init and show them on the dispose… You may want to update your script for all your fans 🙂
Hi there, this looks like a great function but it doesn’t appear to work.
I’ve tried using each of your 5 examples and none of them work!
The only thing that appears to work is if I try and trigger the overlay from an <a> element and I did that by copying the inline javascript (christ there was a lot of it lol) from your ‘demo’ link.
Any ideas any one why using the anchor works but just pasting in any of the above example code doesn’t work?
I want create an overlay with a checkbox and a Ok button. I need to close the overlay when press the Ok button and verify in the checkbox was checked.
Do you know how to do that?
Thanks,