06/05/2009

JavaScript: jQuery Plugin to fade Background but not Content: no css hacks, no *.png files, no problems ...

UPDATE: the toNum method must be changed to this:

function toNum(strNum) {
if (strNum && strNum != "") {
var i = parseFloat(strNum);
if (i.toString() == "NaN")
return 0;
else
return i;
}
return 0;
};


I scoured the web in search of a jQuery plugin that allows me to fade the background but not the contents of a div. I found this article: Cross Browser Transparent Background with jQuery, no css hacks, no *.png files by Mihaistancu and noted that there were a lot of problems with the plugin. It didn't work for me -> but I'm sure it's great code once I figure out the particulars.

I decided to write my own plugin that can take some of these issues into account. The below jQuery plugin has been tested in IE7, Firefox, Opera and Safari and it works.

It takes padding and borders into account so your padding will be enforced and so will your background borders (background can have borders!!). Infact, anything that is not a child element will be applied to the background fade.

How it works:
1) Get the dimensions of TheDiv we want to fade (top, left, height, width - if these are not set in css it will default to the default style for that html element type).
2) Get the inner html of TheDiv and add it to a NewDiv (with id: TheDiv.id + "_content"), and append that NewDiv to TheDiv's parent.
3) Fade TheDiv out ...

Give it a shot and let me know what you think.

You can call the plugin like so:

$(document).ready(function() {
$("#outer").fadeBack();
});

You can download a zip file example /plugin from my Windows Live Space here.

You can see the raw plugin source code below:

(function($) {


$.fn.fadeBack = function(options) {

var _s = $.extend($.fn.fadeBack.defaultOptions, options);

return this.each(function() {

var t = $(this);
var oh = t.height();
var ow = t.width();
var ih = t.html();
var p = t.parent();
var tl = t.position();
var id = t[0].id + "_content";

t.css({ height: oh, width: ow }).html("").fadeTo("fast", _s.opacity);

var padding = dimSum(getPadding(t), getBorderSizes(t));

var ncss = { top: tl.top, left: tl.left,
position: "absolute", height: oh, width: ow,
paddingTop: padding.top, paddingBottom: padding.bottom,
paddingLeft: padding.left, paddingRight: padding.right };

$("
" + ih + "
").css(ncss).appendTo(p);

});

function dimSum(dim1, dim2) {
return { top: dim1.top + dim2.top,
bottom: dim1.bottom + dim2.bottom,
left: dim1.left + dim2.top,
right: dim1.right + dim2.right
}
};

function getBorderSizes(sel) {
return {
top: toNum(sel.css("borderTopWidth")),
bottom: toNum(sel.css("borderBottomWidth")),
left: toNum(sel.css("borderLeftWidth")),
right: toNum(sel.css("borderRightWidth"))
};
};

function getPadding(sel) {
return { top: toNum(sel.css("paddingTop")),
bottom: toNum(sel.css("paddingTop")),
left: toNum(sel.css("paddingLeft")),
right: toNum(sel.css("paddingRight"))
};
};

function toNum(strNum) {
if (strNum && strNum != "") {
var i = parseFloat(strNum);
if (i.toString() == "NaN")
return 0;
else
return i;
}
return 0;
};

}

})(jQuery);

$.fn.fadeBack.defaultOptions = { opacity: 0.4 }

Over and Out

7 comments:

Matt Stark said...

I should also add, opacity is an optional parameter. To set a user defined opacity for the background try this jQuery call:

$(".fadeBack").fadeBack({ opacity: 0.7 });

Booooaaaaaammmmmmooooooo

Over And Out

Matt Stark said...

One last thing ... if the outer DIV is smaller than the inner DIV, you will have a problem ...

I could trap the resize event and resize the background within the plugin but to be honest, this is fine for what I'm using it for and compressed this js file would be minuscule.

Over And Out

Vitor said...
This comment has been removed by the author.
Vitor said...

You are the man!

How can you set the opacity without the animation?

Matt Stark said...

Thanks Mang - That's a bit of a loaded question though:

You can set the opacity without the fadeTo operation by modifying the line from fadeTo to .css({'opacity', _s.opacity}); // let me know if that doesn't work - on my crappy iPhone can't code test

BUT::: That won't ensure the background is translucent on page load - the page will still have to be loaded BEFORE the JavaScript runs to make the background translucent; Users will see a flash from an opaque background to a translucent background on every page load which IMHO is not as nice as opaque fadeTo translucent animation.

If you wanted the background to be translucent on page load without this plugin you'd have to apply the same CSS selectors server side using a transparent png with css fixes for browser incompatabilities - is certainly possible to replicate but more painful to tune (use a developer toolbar like IE Dev or Firebug to inspect the example page).

If you can explain why you don't want the animation I may be able to give a better alternative.

That being said, this plugin solves the text height issue for dynamic content. Absolute coordinates are used to orient the foreground over the fixed sized background - which is all done based on how each different browser renders the text (works on my iPhone) which is why it is always perfect. I'm do not think there is any server side or static css based solution to this problem (at least as long as IE6 is around:)).

Let me know if you have any other jQuery / .Net / CSS questions.

Over and Out

Anonymous said...

Great work.

Anonymous said...

I truly believe that we have reached the point where technology has become one with our society, and I am fairly certain that we have passed the point of no return in our relationship with technology.


I don't mean this in a bad way, of course! Ethical concerns aside... I just hope that as the price of memory falls, the possibility of downloading our memories onto a digital medium becomes a true reality. It's one of the things I really wish I could experience in my lifetime.


(Posted on Nintendo DS running [url=http://quizilla.teennick.com/stories/16129580/does-the-r4-or-r4i-work-with-the-new-ds]R4i SDHC[/url] DS FFOpera)