This was sitting in my “waiting to be published” stuff for a LONG time. I meant to clean it up and include the images I used in my original example, but I never got around to it, so I’m just going ahead and publishing it “as is”.
I decided to create a new way to do snowy backgrounds. I say ‘new’, but surely I’m not the first person ever to do it this way. So, new to me anyway. Below is the process I took… a sort of tutorial for anyone interested. It’s important to note that you could apply this to any/every page on a site, simply by putting the script in an external file and linking it in, calling the init method with the id of a container element, and as long as the path to the images is accessible from each page. Feel free to use this in any way you like (including the images). There are a couple of style rules that were required for this to work (particularly with IE).
First, I decided that I wanted a “layered” snowy effect. The “closest” layer would have the largest flakes, the next layer would have smaller flakes, and the next layer would have even smaller flakes. Each layer is going to fall at a slightly different rate, which is more realistic to what falling snow looks like.
So first I created the closest image. It’s 800×600, has a transparent background, and the flakes are just white circles. I made this using GIMP in about 2 minutes. It’s nothing fancy, just random dots. I made it really tall and wide to try and hide the pattern when this repeats. This first image is snow0.gif.
Next, I needed smaller flakes for the next layer. I just scaled the first image down to 400×300 and saved it as snow1.gif.
For the last level, I again just scaled the image down to 200×150 and saved it as snow2.gif.
Next, I dynamically created the “layers” using JavaScript. Each layer is a div element. Each layer is absolutely positioned to fill the entire width and height. The images are applied as background images to the layers, and the layers are given different z-indexes, so the ‘closer’ layers are on top of the others. With the attached images, it probably doesn’t matter much.
But if your snow flakes had some sort of border or different coloring, you would be able to see the larger flakes falling in front of the smaller flakes.
Because I’m using absolute positioning, I needed to also adjust the content of my pages to also be absolutely positioned, so it could sit on top of my snow. I’m not nuts about that, and if I really wanted to, I might be able to come up with a solution that didn’t use absolute positioning and instead just copied the main body content into one of the snow layers (with each layer nested in another layer). But, hey, this was just for fun.
Finally, I setup an interval to adjust the background postition of each layer, which is what gives it a “falling snow” effect. I currently have it set at every 175ms, but you can adjust it as you like for a balance of performance and appearance (I wouldn’t go above 500 though as it will look too choppy). With each interval, it’s not doing anything too intensive. It’s basically just adjusting the background position and setting the style for each layer. But even so, it will rev up CPU cycles as you set a smaller
interval.
Below is the sample page. Enjoy.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset:utf-8">
<title>Snow Example</title>
<style type="text/css">
body {
background: #ccc; /* Need some color other than white to see the snow */
margin: 0; /* Need to remove margin and padding for IE */
padding: 0;
height: 100%; /* Need a defined height on the body so IE fills page */
}
/* These styles have nothing to do with functionality and can be deleted */
#container {
margin: 2em;
border: 3px solid black;
background: #fff;
padding: 2em;
font-family: arial,sans-serif;
}
</style>
<!-- Optional: put this in an external script file -->
<script type="text/javascript">
/**
* Setup a namespace. I've chosen FOTI, as that's unlikely to conflict with
* any other global methods.
*/
var FOTI = function() {
// Create the 'background' container objects
var snow = [ document.createElement("div"),
document.createElement("div"),
document.createElement("div") ];
// Define a counter that will be incremented with each movement of snow
var inc = 0;
// Variable to hold the number of snow layers
var n = 0;
// Variable to hold the different style settings
var styleRules = [ "background-position:0px 0px",
"background-image:none",
"z-index:0",
"background-repeat:repeat",
"position:absolute;",
"top:0",
"left:0",
"height:100%",
"width:100%",
"padding:0",
"margin:0" ];
// Variable to hold instances of the style setting for each layer
var styleInstances = [];
// A small array copying method
function copyStyles( arr ) {
var that = [];
for( var i = 0; i < arr.length; i++)
{
that[i] = arr[i];
}
return that;
}
return {
/**
* Our snow initialization method. Note, this assumes GIF images.
* @param {String} container The id of the container element which will
* be absolutely positioned on top of our snowy background.
* @param {String} pattern The pattern of the files to be used for the
* background images. For example, if "snow" is passed as the
* value, then snow0.gif, snow1.gif, etc. will be the files
* @param {String} imgExt The file extension of the images to be used.
* If no value is passed, the default "gif" will be used.
* used.
* @dependency For each layer created, there must be an image named
* snowX.gif, where X is the layer number (starting at 0).
*/
initSnow : function(container, pattern, imgExt) {
var b = document.getElementsByTagName("body");
var c = document.getElementById(container);
var pattern = pattern || "snow";
var imgExt = imgExt || "gif";
if( !c ) { return; } // No container means no snow for you!
n = snow.length;
for( var i = 0; i < snow.length; i++ )
{
// Customize the styles for each snow layer
styleRules[1] = "background-image:url(" + pattern + i + "." + imgExt + ")";
styleRules[2] = "z-index:" + (n - i);
styleInstances[i] = copyStyles(styleRules);
// Set the style attribute for the layer
FOTI.domSetAttribute( snow[i], "style", styleInstances[i].join(";") );
// Insert the layer into body. Doesn't matter where since
// we're absolutely positioning them.
b[0].appendChild(snow[i]);
}
// Adjust the container style to be 'above' our snow layers
FOTI.domSetAttribute( c, "style", "position: absolute; top: 0; left: 0; z-index: " + (n+1) );
// Set the snow in motion!
setInterval("FOTI.fall()",175);
},
/**
* Adjust the snowy background images to give the appearance of falling
* snow.
*/
fall : function() {
// Increment the counter
inc++;
for( var i = 0; i < n; i++ )
{
// Adjust the background position for this layer
styleInstances[i][0] = "background-position:" + (2 * inc) + "px" + (2 * (inc * (n-i))) + "px";
FOTI.domSetAttribute( snow[i], "style", (styleInstances[i]).join(";") );
}
},
/**
* Helper function to set an attribute on an element.
*/
domSetAttribute : function( el, attr, val ) {
var attrNode = el.getAttributeNode(attr);
if (attrNode)
{
// IE is giving me problems with this.
// Member not found. I hate you IE!
//attrNode.value = val;
if( attr != "style" )
{
attrNode.value = val;
}
else
{
el.style.cssText = val;
}
}
else
{
el.setAttribute(attr, val);
}
}
};
}();
// Once the page is loaded, start the snow machine!
window.onload = function(){FOTI.initSnow("container","snow","gif");};
</script>
</head>
<body>
<div id="container">
Let it snow!
</div>
</body>
</html>




No user commented in " Snowy Backgrounds "
Follow-up comment rss or Leave a TrackbackLeave A Reply