Procedural Shadow Effect For Your Site Logo

Do you notice anything dynamic about this logo? If not try moving your mouse around it.

Click & Drag Me

png object
png alpha

Still nothing? TURN JAVASCRIPT ON!

If you do in fact see this dynamic shadow effect working around this simple logo then this is what we are going to be talking about today! So get your JavaScript hats on cause here we go.

Ok just so I don’t get flamed here, anybody of course you could use flash to pull something like this off but by using flash you are more limited… anyone mad yet? Let me explain, in the above example you can effect the shadow anywhere on the page with ease. You can also can place and drag the logo container anywhere on the page and still receive perfect shadow reaction.

If created in flash then our shadow effect could only be preformed once a user has move their mouse into the actual flash player. You could create a full page flash version of this but then you have to create the rest of your site in flash and that’s a HUGE NO NO for SEO!

So here we are, best of both worlds using JavaScript or rather W3C DOM Scripting and creating something very unique and elegant.

HTML – CSS Portion

Lets talk about the structure of this little guy:

Click & Drag Me

Here are the basics, we have a div block with an id of wrap and its our main container for the logo and shadow pieces. Within this first div block is a second div block that has an id of element. This second block acts as our two logo images container but also is what makes up our shadow.

In this example we have two images both of the file type PNG24 and have alpha transparency. Our first image is our actual logo, in our example its the letter “D” this image is completely transparent except for the actual shape of the letter “D”. The second image is also using alpha transparency but into an inverted version compared to our first image. So we have two images one that uses alpha transparency to form our logo or rather red letter “D” and the other is a white image that too uses alpha transparency to cut out a shape of the letter “D”.

object
alpha

Notice that the first image is smaller than the second. This is important to keep in mind but and we will get back to why this is so important here in a bit.

Take a look at this diagram of how the images are layered and carry their alpha transparency to one another.

fig1

Ok so now that we have and idea of how these two images transparency’s work work off one another lets look at how we place them into our html.

Make your html now look like this:

Click & Drag Me

Ok so just like in the above figure we have our two images stacked on top of each other. Our first image is named “object.png” and our second “alpha.png” one makes an object (our red letter “D”) and the other creates and alpha mask of the other.

The second image (alpha.png) carry’s some very important inline styles that must remain inline in order for our JavaScript to perform our shadow effect properly. Both top and right are set to -6px; and our left, bottom are set to null or nothing. We set both the top and right to -6px to offset our alpha.png and align it to our object.png image due to alpha.png being 12px larger than object.png. The reason there is no setting for the left and bottom styles is because these will be filled in dynamically by our javascript so its best to leave them empty for now.

Lets look at the rest of our CSS that finishes off our dynamic logos structure. Add the following to your documents header tags.

%MINIFYHTMLb160634b63d0c49023114c222238ba2c19%

Ok lets run over why these styles are important to our desired results. First we have our div block element “wrap” and its style rule that gives it both a” width” and “height” of 150px. You can change this to what ever you desire.

Our next rule is for our “element” div block and it too states a width and height but only of 128px and we use 128px because our object.png image is 128px by 128px. We also set a position of relative to give us the ability to use children elements that have a position of absolute with out breaking them out of our structured flow. Our last two important styles are the background-color and overflow styles, we set our background color to be that of a darker one such as a shadow or shade. We set our overflow style to be hidden so that our alpha.png image that is larger than 128px will be hidden but also not bring about scroll bars.

Ok our next CSS rule is called “#object” and its for our element “object” or object.png and we set its position to be absolute so our JavaScript can perform our shadow effect. We have a both a top and left of 0px because with the position of absolute we want to make sure our “object” element is always in the upper left hand corner at all times. Our last rule is working in conjunction with our position of absolute and states our browser rendering hierarchy over any other elements that have a z-index style lower than 1.

Of course our last style rule is for our element “alpha” or alpha.png and it too is set to position of absolute and a z-index of 0. Again the z-index is set to a lower number than that of our #object rule in order to stack our object.png image over our alpha.png image respectively.

JavaScript Portion

There are two actions at distance in play here. Our mouse is feeding a JavaScript function its coordinates (X,Y) of its position on the page while this function makes sure our two images react accordingly.

In order for our mouse to event receive its coordinates a document must have a point of orgin for these coordinates.
The point of orgin is the location of where both our X and Y intersect resulting in both X and Y to be zero. So we make our logo be the point of orgin for our mouse’s coordinates that feed to our JavaScript function.

Why we make our logo the point of orgin is so that placement of the logo on the page results in perfect reaction from both object and mouse.

Here is the JavaScript that handles our point of orgin.

var divObj;
document.onmousemove=getMouseCoordinates;

function zxcMse(zxcevt){
 if(!zxcevt) var zxcevt=window.event;
 if (document.all) return [zxcevt.clientX+zxcDocS()[0],zxcevt.clientY+zxcDocS()[1]];
 return [zxcevt.pageX,zxcevt.pageY];
}

function zxcDocS(){
 if (!document.body.scrollTop) return [document.documentElement.scrollLeft,document.documentElement.scrollTop];
 return [document.body.scrollLeft,document.body.scrollTop];
}

function zxcPos(zxcobj){
 zxclft=zxcobj.offsetLeft;
 zxctop=zxcobj.offsetTop;
 while(zxcobj.offsetParent!=null){
  zxcpar=zxcobj.offsetParent;
  zxclft+=zxcpar.offsetLeft;
  zxctop+=zxcpar.offsetTop;
  zxcobj=zxcpar;
 }
 return [zxclft,zxctop];
}

I wont go too much into this but basicly it creates an event handler that is gathering our mouse coordinates and point of orgin and relocating them to be that of an element.
For us to use this event handler though we must also setup a function that shifts our alpha image accordingly. Here is this function:

function getMouseCoordinates(event)
{
	var ev = event || window.event;
	var element = document.getElementById("element");
	var alpha = document.getElementById("alpha");
	var mse=zxcMse(ev);
	var pos=zxcPos(element)
  	var cx=pos[0]+element.offsetWidth/2;
  	var cy=pos[1]+element.offsetHeight/2;
  	var x=(mse[0]-cx);
  	var y=(mse[1]-cy);
}

This function has three parts to it that we must pay close attion to.

  • The first part is that the function is named “getMouseCoordinate” and is calling to our event handler “event”.
  • The next part is the element we are pointing too named “element”.
  • The last part is the second element we are pointing too named “alpha”.

Basicly what this is doing is takeing our “element” and “alpha” elements and setting the point of orgin for our mouse coordinates to them. In theroy now what ever coordinates we recive from our mouse will always be centered around these two objects.

The next thing we must create is our conditions for shifting the alpha image around based off these coordinates.

I never said this was going to be easy…

Lets start talking about what this JavaScript condition that shifts our alpha image is actuly doing. In a nut shell its stateing the following based on the mouse coordinates its recives.

if(x coordinate is greater than 50)

{

	Shift alpha image to the left by so many pixels.

}
else if (x is greater than 75)

{

	Shift alpha image left again and by so many pixels.

}

This conditional statement is also true for our negative numbers as our point of origin falls into both negative and positive numbers along both X and Y. Here is the above examples alpha image conditions for shifting both left right and top bottom.

	///////////////
	//RIGHT SHIFT//
  ///////////////
	if(x<-100){
		alpha.style.left="";
		alpha.style.right="-11px";
	}
	else if(x<-80){

		alpha.style.left="";
		alpha.style.right="-10px";
	}
	else if(x<-60){

		alpha.style.left="";
		alpha.style.right="-9px";
	}
	else if(x<-40){

		alpha.style.left="";
		alpha.style.right="-8px";
	}
	else if(x<-20){

		alpha.style.left="";
		alpha.style.right="-7px";
	}

	//////////////
	//LEFT SHIFT//
	//////////////
 	if(x>100){
		alpha.style.right="";
		alpha.style.left="-11px";
	}
 	else if(x>80){
		alpha.style.right="";
		alpha.style.left="-10px";
	}	

 	else if(x>60){
		alpha.style.right="";
		alpha.style.left="-9px";
	}
 	else if(x>40){
		alpha.style.right="";
		alpha.style.left="-8px";
	}
 	else if(x>20){
		alpha.style.right="";
		alpha.style.left="-7px";
	}

	////////////////
	//BOTTOM SHIFT//
	////////////////
	if(y<-100){
		alpha.style.top="";
		alpha.style.bottom="-11px";
	}
	else if(y<-80){
		alpha.style.top="";
		alpha.style.bottom="-10px";
	}
	else if(y<-60){
		alpha.style.top="";
		alpha.style.bottom="-9px";
	}
	else if(y<-40){
		alpha.style.top="";
		alpha.style.bottom="-8px";
	}
	else if(y<-20){
		alpha.style.top="";
		alpha.style.bottom="-7px";
	}

	/////////////
	//TOP SHIFT//
	/////////////
	if(y>100){
		alpha.style.bottom="";
		alpha.style.top="-11px";

	}
	else if(y>80){
			alpha.style.bottom="";
			alpha.style.top="-10px";

	}
	else if(y>60){
			alpha.style.bottom="";
			alpha.style.top="-9px";

	}
	else if(y>40){
			alpha.style.bottom="";
			alpha.style.top="-8px";

	}
	else if(y>20){
			alpha.style.bottom="";
			alpha.style.top="-7px";
	}

Two thing to note here befor you are off to trying to edit this huge conditional statment. First each shifting direction steeps 5 times and based on 5 diffrent numbers given to it by our mouses coordinates. Each number shifts our alpha image either a little less or more in the its designated direction.

Remeber how we talked about the html structure of this above and I told you that our alpha image has to be larger that our actule displaying area. This is true now because we must use this extra image size to allow a proper shifting and seamless bleed off the containers edges.

Here is our script compleated:

var divObj;
document.onmousemove=getMouseCoordinates;

function zxcMse(zxcevt){
 if(!zxcevt) var zxcevt=window.event;
 if (document.all) return [zxcevt.clientX+zxcDocS()[0],zxcevt.clientY+zxcDocS()[1]];
 return [zxcevt.pageX,zxcevt.pageY];
}

function zxcDocS(){
 if (!document.body.scrollTop) return [document.documentElement.scrollLeft,document.documentElement.scrollTop];
 return [document.body.scrollLeft,document.body.scrollTop];
}

function zxcPos(zxcobj){
 zxclft=zxcobj.offsetLeft;
 zxctop=zxcobj.offsetTop;
 while(zxcobj.offsetParent!=null){
  zxcpar=zxcobj.offsetParent;
  zxclft+=zxcpar.offsetLeft;
  zxctop+=zxcpar.offsetTop;
  zxcobj=zxcpar;
 }
 return [zxclft,zxctop];
}

function getMouseCoordinates(event)
{
	var ev = event || window.event;
	var element = document.getElementById("element");
	var alpha = document.getElementById("alpha");
	var mse=zxcMse(ev);
	var pos=zxcPos(element)
  	var cx=pos[0]+element.offsetWidth/2;
  	var cy=pos[1]+element.offsetHeight/2;
  	var x=(mse[0]-cx);
  	var y=(mse[1]-cy);

///////////////
//RIGHT SHIFT//
///////////////
if(x<-100){alpha.style.left="";	alpha.style.right="-11px";}
else if(x<-80){alpha.style.left="";	alpha.style.right="-10px";}
else if(x<-60){alpha.style.left="";	alpha.style.right="-9px";}
else if(x<-40){alpha.style.left="";	alpha.style.right="-8px";}
else if(x<-20){alpha.style.left="";	alpha.style.right="-7px";}

//////////////
//LEFT SHIFT//
//////////////
if(x>100){alpha.style.right=""; alpha.style.left="-11px";}
else if(x>80){alpha.style.right=""; alpha.style.left="-10px";}
else if(x>60){alpha.style.right=""; alpha.style.left="-9px";}
else if(x>40){alpha.style.right=""; alpha.style.left="-8px";}
else if(x>20){alpha.style.right=""; alpha.style.left="-7px";}

////////////////
//BOTTOM SHIFT//
////////////////
if(y<-100){ alpha.style.top="";	alpha.style.bottom="-11px";}
else if(y<-80){alpha.style.top=""; alpha.style.bottom="-10px";}
else if(y<-60){alpha.style.top=""; alpha.style.bottom="-9px";}
else if(y<-40){alpha.style.top=""; alpha.style.bottom="-8px";}
else if(y<-20){alpha.style.top=""; alpha.style.bottom="-7px";}

/////////////
//TOP SHIFT//
/////////////
if(y>100){alpha.style.bottom=""; alpha.style.top="-11px";}
else if(y>80){alpha.style.bottom=""; alpha.style.top="-10px";}
else if(y>60){alpha.style.bottom=""; alpha.style.top="-9px";}
else if(y>40){alpha.style.bottom=""; alpha.style.top="-8px";}
else if(y>20){alpha.style.bottom="";alpha.style.top="-7px";}
}

Ok last thing I want to talk about is that in the above conditional statment I did not include the portions that create the highlight’s in the above demo. If you would like to see how this was created then download copy of this compleat script and demo in action and have fun!

DOWNLOAD A COMPLETE COPY OF THE SCRIPT

Thanks.

Devin R. Olsen


Devin R. Olsen

Located in Portland Oregon. I like to teach, share and dabble deep into the digital dark arts of web and game development.

More Posts

Follow Me:
TwitterFacebookGoogle Plus