Monday, January 08, 2007

Cross-Browser Gradient Background (without image, without series of div elements)

Introduction

Couple of days ago I decide to modify my web page and put a gradient background that will work with different browsers. Sounds simple, I thought that too. After search through the internet I realize that only the filters of IE can do exactly what I wanted. Unfortunately the filter extension work only with IE. For Cross-Browser gradient there are couple of solution on Internet but none of them is as elegant as the filters in the IE.
Here are couple of solutions that I found on internet:
secretgeek.net/ColorWebService.asp
(uses the web service to create a gradient picture on the fly)
www.slayeroffice.com/code/gradient/
(uses the series of div elements)

Somehow, I wasn't comfortable with any of the solutions above. So I come up with idea to create a gradient background using the canvas. I was surprised that there isn't any post on the web about using the canvas for drawing the gradient background. So after a long search, learning and digging trough the poor documentation of the JavaScript, I finally have done it. A big help was the Aptana that made life easier with the JavaScripts. It has the same IDE as Eclipse, it's free and it has Intellisense.

Gradient background using the canvas
The idea is to use the filter property for IE and the canvas tag for browsers that are not IE. For FF,Opera we create two div objects, one that will have background image and other that will has the contents of the body of the document. After that a gradient is drawn into the canvas and then copied into the background image. The background image width/height is set to 100% so we don't have to worry about resizing. Here is the script:


function drawGradient(startColor, endColor){
try{
// get window size
var iWidth = 0, iHeight = 0;
if( typeof( window.innerWidth ) == 'number' ) {
//Non-IE
iWidth = window.innerWidth;
iHeight = window.innerHeight;
} else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
//IE 6+ in 'standards compliant mode'
iWidth = document.documentElement.clientWidth;
iHeight = document.documentElement.clientHeight;
} else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
//IE 4 compatible
iWidth = document.body.clientWidth;
iHeight = document.body.clientHeight;
}

// set the gradiant background
if (document.all && !window.opera) {
// for IE use DXImageTransform
document.body.style.filter="progid:DXImageTransform.Microsoft.Gradient(startColorStr='" + startColor + "', endColorStr='" + endColor + "', gradientType='0')";
} else {

// set document margin/pading
document.body.style.overflow = 'hidden';
document.body.style.padding = '0px';
document.body.style.margin = '0px';

// create DIV that will be used for the canvas and background Image
var oDiv = document.createElement("DIV");
oDiv.style.position = 'absolute';
oDiv.style.top = '0px';
oDiv.style.left = '0px';
oDiv.style.height = '100%';
oDiv.style.width = '100%';
oDiv.style.overflow = 'hidden';
oDiv.style.zIndex=1;
oDiv.setAttribute("id","canvasDiv");

// create DIV that will contain the whole document
var oDocDiv = document.createElement("DIV");
oDocDiv.style.position = 'absolute';
oDocDiv.style.top = '0px';
oDocDiv.style.left = '0px';
oDocDiv.style.height = '100%';
oDocDiv.style.width = '100%';
oDocDiv.style.overflow = 'hidden';
oDocDiv.style.zIndex=2;
oDocDiv.setAttribute("id","canvasDiv");
oDocDiv.innerHTML = document.body.innerHTML;
//document.body.innerHTML ="";
document.body.appendChild(oDiv);
oDiv.appendChild(oDocDiv);

// create canvas
var c = document.createElement("canvas");
c.setAttribute("width",iWidth);
c.setAttribute("height",iHeight);
c.setAttribute("top",0);
c.setAttribute("left",0);
c.setAttribute("id","cl");
oDiv.appendChild(c);
var ctx = c.getContext("2d");

// create the gradient
var gradient= ctx.createLinearGradient(0,0,0,iHeight)
gradient.addColorStop(0, startColor)
gradient.addColorStop(1, endColor);
ctx.fillStyle = gradient;
ctx.fillRect(0, 0,iWidth,iHeight);

// copy the canvas into a image object
var img = document.createElement("img");
img.style.position = 'absolute';
img.setAttribute("width","100%");
img.setAttribute("height","100%");
img.setAttribute("top",0);
img.setAttribute("left",0);
img.setAttribute("id","bkgImage");
img.setAttribute("border",0);
img.style.zIndex=1;
oDiv.appendChild(img);
var imgData = c.toDataURL();
img.src = imgData;
img.style.zIndex=0;
oDiv.style.zIndex=0;

// remove the canvas
oDiv.removeChild(c);
}
} catch(e){
//alert(e);
}
}

To see it in action click here.

Pros: easy change of the colors; no need of gradient picture; fast creation of the gradient; auto resizing; gradient is created based on the size of the window.
Cons: uses the JavaScript; not supported by Netscape; created a 2 additional div tags when the page is not shown in IE.

Note: This script is not working in Netscape. So far, the toDataURL method is not supported in the Netscape.

References:
http://developer.mozilla.org/en/docs/Canvas_tutorial
http://developer.apple.com/documentation/AppleApplications/Reference/SafariJSRef/Classes/Canvas.html#//apple_ref/js/Canvas.clearRect
http://www.mozilla-japan.org/events/2006/interop-tokyo/presentations/mscott/
http://virtuelvis.com/archives/2005/10/canvas-mandelbrot
http://tech.groups.yahoo.com/group/canvas-developers/