As often, this is a problem that seems much simpler then it turns out to be when you start trying to tackle it. I gave it a go, and though it is not yet 100% to my liking, I will share my results with you.
First I should note that jQuery is perfectly valid cross browser JavaScript, so I can not think of any good reason not to use it. Definitely if you load it from Google CDN or similar, it will probably already be in your users cache. So I went ahead and wrote a small jQuery plugin (my old-school JavaScript is just way to rusty to be honest).
First the code:
// jQuery plugin to create overlays
// apply to any container that contains DOM elements to be overlayed
$.fn.overlayDiv = function() {
// remove any old overlays (could be there on resize)
$(this).find('.overlay').remove();
// loop trough the remaining children
$(this).find('*').each(function() {
// cache some variables
var $el = $(this);
var $parent = $el.parent();
// make the parent relative, if not yet absolute or fixed, for easy positioning
if ($parent.css('position') !== 'fixed' && $parent.css('position') !== 'absolute') {
$parent.css('position', 'relative');
}
// prepare the css
var css = {};
css.zIndex = $el.css('z-index');
css.position = $el.css('position') == 'fixed' ? 'fixed' : 'absolute';
css.display = 'block';
// check if inline or block, and calculate settings appropriately
if ($el.css('display') == 'inline') {
// -- inline
// clone the element and render it on one line
var $clone = $el.clone();
$clone.css({
width: 'auto',
display: 'block',
whiteSpace: 'nowrap'
});
$clone.insertAfter($el);
// compare height of element and clone
if ($el.outerHeight(true) == $clone.outerHeight(true)) {
// if the $el is on a single line
css.width = $el.outerWidth(true);
css.height = $el.outerHeight(true);
css.top = $el.position().top;
css.left = $el.position().left;
// apply the styling to an overlay div and include it in the DOM
$('<div class="overlay"></div>').css(css).insertAfter($el);
} else {
// if the $el is on multiple lines (we need up to 3 divs to overlay)
// -- this part of the code needs improving --
var lineHeight = $clone.outerHeight();
var totalWidth = $clone.outerWidth();
var lines = $el.outerHeight() / lineHeight;
var maxWidth = $parent.width();
// top overlay
css.width = maxWidth - $el.position().left;
css.height = lineHeight;
css.top = $el.position().top;
css.left = $el.position().left;
$('<div class="overlay top"></div>').css(css).insertAfter($el);
// bottom overlay
css.width = totalWidth - css.width - ((lines-2) * maxWidth);
css.top = css.top + (lineHeight*lines);
css.left = 0;
$('<div class="overlay bottom"></div>').css(css).insertAfter($el);
// center overlay
css.width = maxWidth;
css.height = (lines- 2) * lineHeight;
// -- /needs improving -- //
}
$clone.remove();
} else {
// -- block
css.width = $el.outerWidth(true);
css.left = $el.position().left;
// -- height and top might need to improved if you want collapsing margins taken into account
css.height = $el.outerHeight(true);
css.top = $el.position().top;
// apply the styling to an overlay div and include it in the DOM
$('<div class="overlay"></div>').css(css).insertAfter($el);
}
});
}
// when the window is loaded or resized (not just ready, the images need to be there to copy their position and size)
$(window).on('load resize', function() {
// apply the overlay plugin to the body to cover all elements, or recalculate their positioning
$('body').overlayDiv();
});
Plenty of comments in there, so I think it should be understandable, but feel free to ask if you want any clarification.
You can see the code in action over here:
http://jsfiddle.net/pP96f/7/
About the 2 remaining issues:
- The biggest problem is the inline elements that span across multiple
lines. If you want to cover only the text inside the element, you
will need up to three separate overlays to achieve this. I was
struggling with the dimensions (especially the width of the bottom div) and eventually i gave up. Any input
would be appreciated!
- A smaller issue is the one of the collapsing margins. This should not be to hard to tackle, but I was not sure how you wanted this handled. (And I already spend way to much time on this question...)
Hope my input can be of assistance!
edit:
For a version that allows you to select the specific elements you want to overlay, and not just select a parent and have all the children(recursivly) overlayed, have a look at this slightly altered version of the code: http://jsfiddle.net/ARWBD/2/