Hey guys... and Merry Christmas!
Years ago, I worked in a
company where the CEO had this endearing habit of drafting pompous emails during festive seasons to wish us happy-whatever-holidays and pontificate on the meaning of the festival itself. Chinese New Year, Easter, and yes, Christmas. Most of us barely even looked, though some might draft a thank-you email out of courtesy. Some went the extra mile and even read through it.
Well, you know, it takes all sorts.
So one Christmas, I had this idea. If I was going to receive yet
another CEO festive letter, I might as well make something of it. I made a nice web template to place the contents of the letter, and even made the background change when the user scrolled. Because it's a really
long, rambling message, see? Before I could pitch this, however, shit happened and I was no longer working at the company.
Still, there's no sense in letting a perfectly good idea go to waste, so, let's have at it!
Start with a basic HTML setup.
<!DOCTYPE html>
<html>
<head>
<title>A Letter From the CEO</title>
<style>
</style>
<script>
</script>
</head>
<body>
</body>
</html>
We'll go ahead and style the body tag first. Setting the
margin property to 0 will reset whatever cross-browser properties we need for this web tutorial. The background will be a somewhat pale
blue.
<style>
body
{
margin: 0;
background-color: #AAAAFF;
}
</style>
Back to the HTML, add two divs into the body. Both will have the CSS class
container. The first will also be styled using the CSS class
background, and the second one,
foreground.
<body>
<div class="background container">
</div>
<div class="foreground container">
</div>
</body>
Now we add code for those styles.
container's
position property is
absolute and takes up the whole of the screen.
background's
z-index property is lower than that of
foreground's. In essence, we made two divs which lie right on top of each other. But since neither of them have a background color, you won't see any difference just yet.
<style>
body
{
margin: 0;
background-color: #AAAAFF;
}
.container
{
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
.background
{
z-index: 10;
}
.foreground
{
z-index: 20;
}
</style>
The next thing to add is another div within the second div. It will be styled using
content.
<body>
<div class="background container">
</div>
<div class="foreground container">
<div class="content">
</div>
</div>
</body>
Let's style this.
content will take up 40% of screen space. The
margin property has been set so that it sits nicely in the middle. We set the background color to
white. The
padding,
text-align and
font-face properties are up to you; they don't really affect anything other than the visuals.
body
{
margin: 0;
background-color: #AAAAFF;
}
.container
{
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
.content
{
width: 40%;
min-height: 100%;
margin: 0 auto 0 auto;
background-color: #FFFFFF;
padding: 1em;
text-align: justify;
font-family: georgia;
}
And here we have a nice div, ready for content!
OK, let's populate this with content. It's
Lorem Ipsum I generated, to simulate the long-ass content.
<body>
<div class="background container">
</div>
<div class="foreground container">
<div class="content">
<h1>Merry Christmas!</h1>
<p>
Dear colleagues,
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec lobortis quis risus non cursus. Sed id posuere erat. Donec augue purus, accumsan fermentum neque in, mollis mattis ligula. Sed ornare, risus vel tristique vestibulum, nisl tellus maximus ex, eget tempor ligula turpis eu nibh. Vestibulum vehicula fringilla elit vel viverra. Aenean hendrerit scelerisque sollicitudin. Cras convallis tellus vitae sapien sagittis, et finibus tortor vestibulum. Donec cursus elit ante, ut ultricies elit cursus eu. Suspendisse ac interdum elit. Praesent lorem augue, sodales a urna ut, mollis vehicula nunc. Proin eu viverra lectus. In ut tortor eget nisi vestibulum euismod vitae eu est. Nullam lacinia, lorem eget dictum vehicula, orci felis dapibus nunc, vitae ornare nisi est ut turpis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec vitae tincidunt mauris. Maecenas id luctus velit.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec lobortis quis risus non cursus. Sed id posuere erat. Donec augue purus, accumsan fermentum neque in, mollis mattis ligula. Sed ornare, risus vel tristique vestibulum, nisl tellus maximus ex, eget tempor ligula turpis eu nibh. Vestibulum vehicula fringilla elit vel viverra. Aenean hendrerit scelerisque sollicitudin. Cras convallis tellus vitae sapien sagittis, et finibus tortor vestibulum. Donec cursus elit ante, ut ultricies elit cursus eu. Suspendisse ac interdum elit. Praesent lorem augue, sodales a urna ut, mollis vehicula nunc. Proin eu viverra lectus. In ut tortor eget nisi vestibulum euismod vitae eu est. Nullam lacinia, lorem eget dictum vehicula, orci felis dapibus nunc, vitae ornare nisi est ut turpis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec vitae tincidunt mauris. Maecenas id luctus velit.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec lobortis quis risus non cursus. Sed id posuere erat. Donec augue purus, accumsan fermentum neque in, mollis mattis ligula. Sed ornare, risus vel tristique vestibulum, nisl tellus maximus ex, eget tempor ligula turpis eu nibh. Vestibulum vehicula fringilla elit vel viverra. Aenean hendrerit scelerisque sollicitudin. Cras convallis tellus vitae sapien sagittis, et finibus tortor vestibulum. Donec cursus elit ante, ut ultricies elit cursus eu. Suspendisse ac interdum elit. Praesent lorem augue, sodales a urna ut, mollis vehicula nunc. Proin eu viverra lectus. In ut tortor eget nisi vestibulum euismod vitae eu est. Nullam lacinia, lorem eget dictum vehicula, orci felis dapibus nunc, vitae ornare nisi est ut turpis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec vitae tincidunt mauris. Maecenas id luctus velit.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec lobortis quis risus non cursus. Sed id posuere erat. Donec augue purus, accumsan fermentum neque in, mollis mattis ligula. Sed ornare, risus vel tristique vestibulum, nisl tellus maximus ex, eget tempor ligula turpis eu nibh. Vestibulum vehicula fringilla elit vel viverra. Aenean hendrerit scelerisque sollicitudin. Cras convallis tellus vitae sapien sagittis, et finibus tortor vestibulum. Donec cursus elit ante, ut ultricies elit cursus eu. Suspendisse ac interdum elit. Praesent lorem augue, sodales a urna ut, mollis vehicula nunc. Proin eu viverra lectus. In ut tortor eget nisi vestibulum euismod vitae eu est. Nullam lacinia, lorem eget dictum vehicula, orci felis dapibus nunc, vitae ornare nisi est ut turpis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec vitae tincidunt mauris. Maecenas id luctus velit.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec lobortis quis risus non cursus. Sed id posuere erat. Donec augue purus, accumsan fermentum neque in, mollis mattis ligula. Sed ornare, risus vel tristique vestibulum, nisl tellus maximus ex, eget tempor ligula turpis eu nibh. Vestibulum vehicula fringilla elit vel viverra. Aenean hendrerit scelerisque sollicitudin. Cras convallis tellus vitae sapien sagittis, et finibus tortor vestibulum. Donec cursus elit ante, ut ultricies elit cursus eu. Suspendisse ac interdum elit. Praesent lorem augue, sodales a urna ut, mollis vehicula nunc. Proin eu viverra lectus. In ut tortor eget nisi vestibulum euismod vitae eu est. Nullam lacinia, lorem eget dictum vehicula, orci felis dapibus nunc, vitae ornare nisi est ut turpis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec vitae tincidunt mauris. Maecenas id luctus velit.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec lobortis quis risus non cursus. Sed id posuere erat. Donec augue purus, accumsan fermentum neque in, mollis mattis ligula. Sed ornare, risus vel tristique vestibulum, nisl tellus maximus ex, eget tempor ligula turpis eu nibh. Vestibulum vehicula fringilla elit vel viverra. Aenean hendrerit scelerisque sollicitudin. Cras convallis tellus vitae sapien sagittis, et finibus tortor vestibulum. Donec cursus elit ante, ut ultricies elit cursus eu. Suspendisse ac interdum elit. Praesent lorem augue, sodales a urna ut, mollis vehicula nunc. Proin eu viverra lectus. In ut tortor eget nisi vestibulum euismod vitae eu est. Nullam lacinia, lorem eget dictum vehicula, orci felis dapibus nunc, vitae ornare nisi est ut turpis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec vitae tincidunt mauris. Maecenas id luctus velit.
</p>
<p class="signoff">
Season's blessings,<br />
Your Chief Executive Officer
</p>
</div>
</div>
</body>
Great. Now we need to scroll to read all of this stuff. But this is where things get interesting...
Let's animate the background!
So my bright idea was to ensure that the background moved each time the user scrolled. But not in a in-your-face kind of way. Something... subtle.
What we do here, is add more divs to the first div. Therefore they will appear behind the Letter from the CEO. Each of these will be styled using the CSS class
snowflake. Six of them will be styled using the CSS class
left, and the other six using CSS class
right.
<div class="background container">
<div class="snowflake left"></div>
<div class="snowflake left"></div>
<div class="snowflake left"></div>
<div class="snowflake left"></div>
<div class="snowflake left"></div>
<div class="snowflake left"></div>
<div class="snowflake right"></div>
<div class="snowflake right"></div>
<div class="snowflake right"></div>
<div class="snowflake right"></div>
<div class="snowflake right"></div>
<div class="snowflake right"></div>
</div>
Here's the CSS code for
snowflake. There is no CSS code for
left or
right; that will be handled via JavaScript. So, the
position property is set to
fixed, which means the div will stay in place even if you scroll. The
transform-origin property is set to dead center of the div. We'll need this because we may be rotating the divs later. After this, you still won't see any visible changes to your screen, so don't bother refreshing.
.foreground
{
z-index: 20;
}
.snowflake
{
position: fixed;
-webkit-transform-origin: 50% 50%;
transform-origin: 50% 50%;
}
.content
{
width: 40%;
min-height: 100%;
margin: 0 auto 0 auto;
background-color: #FFFFFF;
padding: 1em;
text-align: justify;
font-family: georgia;
}
Here are some images I looted off
this site. They will be stored in the
img folder.
|
snowflake1.png |
|
snowflake2.png |
|
snowflake3.png |
Let's write some JavaScript. First, change your body tag to run the
initSnowflakes() function upon loading.
<body onload="initSnowflakes()">
Then write the function.
<script>
function initSnowflakes()
{
}
</script>
We begin by grabbing all the divs that are styled using the CSS class
snowflake, and putting them in an array
snowflakes.
<script>
function initSnowflakes()
{
var snowflakes = document.getElementsByClassName("snowflake");
}
</script>
Then we iterate through the
snowflakes array...
<script>
function initSnowflakes()
{
var snowflakes = document.getElementsByClassName("snowflake");
for (var i = 0; i < snowflakes.length; i++)
{
}
}
</script>
...and change the background of that div to a random image from the
img folder! Of course, to do that, you'll need the
generateRandomNumber() function. Make sure the
backgroundSize property is set to
contain; this is gonna be relevant soon.
<script>
function initSnowflakes()
{
var snowflakes = document.getElementsByClassName("snowflake");
for (var i = 0; i < snowflakes.length; i++)
{
snowflakes[i].style.background = "url(img/snowflake" + generateRandomNo(1, 3) + ".png) left top no-repeat";
snowflakes[i].style.backgroundSize = "contain";
}
}
</script>
Here, I provided the
generateRandomNumber() function for you. Now isn't that nice?
<script>
function initSnowflakes()
{
var snowflakes = document.getElementsByClassName("snowflake");
for (var i = 0; i < snowflakes.length; i++)
{
snowflakes[i].style.background = "url(img/snowflake" + generateRandomNo(1, 3) + ".png) left top no-repeat";
snowflakes[i].style.backgroundSize = "contain";
}
}
function generateRandomNo(varmin, varmax)
{
return Math.floor((Math.random() * (varmax-varmin+1)) + varmin);
}
</script>
You still won't see any results. Not unless you specify the width and height of the divs. For the sake of experimentation, let's set both height and width to 100 pixels.
function initSnowflakes()
{
var snowflakes = document.getElementsByClassName("snowflake");
for (var i = 0; i < snowflakes.length; i++)
{
snowflakes[i].style.background = "url(img/snowflake" + generateRandomNo(1, 3) + ".png) left top no-repeat"
snowflakes[i].style.backgroundSize = "contain";
snowflakes[i].style.width = "100px";
snowflakes[i].style.height = "100px";
}
}
Check out the result now... you see the top left hand corner? It's all twelve divs, now cluster-fucking there because the
left and
top properties have not been specified. But they're big enough that you can see them!
OK, now comment out the last two lines. Those were just to show you stuff. At the end of the function, make a call to the
transitSnowflakes() function. And start creating that function.
function initSnowflakes()
{
var snowflakes = document.getElementsByClassName("snowflake");
for (var i = 0; i < snowflakes.length; i++)
{
snowflakes[i].style.background = "url(img/snowflake" + generateRandomNo(1, 3) + ".png) left top no-repeat"
snowflakes[i].style.backgroundSize = "contain";
//snowflakes[i].style.width = "100px";
//snowflakes[i].style.height = "100px";
}
transitSnowflakes();
}
function transitSnowflakes()
{
}
Here, let's do what we did for
initSnowflakes(). Get all the divs and put them in the
snowflakes array. Then iterate through that array.
function transitSnowflakes()
{
var snowflakes = document.getElementsByClassName("snowflake");
for (var i = 0; i < snowflakes.length; i++)
{
}
}
If the div is styled using
snowflake and
left, set the
left property to a value between 0 to 5%. If it's styled using
snowflake and
right, do this for the
right property.
function transitSnowflakes()
{
var snowflakes = document.getElementsByClassName("snowflake");
for (var i = 0; i < snowflakes.length; i++)
{
if (snowflakes[i].className == "snowflake left")
{
snowflakes[i].style.left = generateRandomNo(0, 5) + "%";
}
if (snowflakes[i].className == "snowflake right")
{
snowflakes[i].style.right = generateRandomNo(0, 5) + "%";
}
}
}
As you can see, some are left of the screen, and some are right! But they're still overlapped. Let's fix that...
We'll generate a value between 0 and 80 % for the
top property.
function transitSnowflakes()
{
var snowflakes = document.getElementsByClassName("snowflake");
for (var i = 0; i < snowflakes.length; i++)
{
snowflakes[i].style.top = generateRandomNo(0, 80) + "%";
if (snowflakes[i].className == "snowflake left")
{
snowflakes[i].style.left = generateRandomNo(0, 5) + "%";
}
if (snowflakes[i].className == "snowflake right")
{
snowflakes[i].style.right = generateRandomNo(0, 5) + "%";
}
}
}
Ah,
now we're talking. Randomly scattered snowflakes!
But you'll notice when you scroll, they change positions. That's expected behavior, but the movement's way too jerky, so let's set the
transition property to time the movement between 5 to 30 seconds. Now when you refresh the page, see how slowly and gracefully the snowflakes move!
function transitSnowflakes()
{
var snowflakes = document.getElementsByClassName("snowflake");
for (var i = 0; i < snowflakes.length; i++)
{
snowflakes[i].style.top = generateRandomNo(0, 80) + "%";
if (snowflakes[i].className == "snowflake left")
{
snowflakes[i].style.left = generateRandomNo(0, 5) + "%";
}
if (snowflakes[i].className == "snowflake right")
{
snowflakes[i].style.right = generateRandomNo(0, 5) + "%";
}
snowflakes[i].style.transition = "all " + generateRandomNo(5, 30) + "s";
snowflakes[i].style.WebkitTransition = "all " + generateRandomNo(5, 30) + "s";
}
}
Let's have some more fun...
Set the
width and
height properties, then rotate the snowflakes in different directions. And set the opacity randomly too.
function transitSnowflakes()
{
var snowflakes = document.getElementsByClassName("snowflake");
for (var i = 0; i < snowflakes.length; i++)
{
snowflakes[i].style.width = generateRandomNo(20, 500) + "px";
snowflakes[i].style.height = generateRandomNo(20, 500) + "px";
snowflakes[i].style.top = generateRandomNo(0, 80) + "%";
snowflakes[i].style.transform = "rotate(" + generateRandomNo(-150, 150) + "deg)";
snowflakes[i].style.WebkitTransform = "rotate(" + generateRandomNo(-150, 150) + "deg)";
snowflakes[i].style.opacity = "0." + generateRandomNo(1, 5);
if (snowflakes[i].className == "snowflake left")
{
snowflakes[i].style.left = generateRandomNo(0, 5) + "%";
}
if (snowflakes[i].className == "snowflake right")
{
snowflakes[i].style.right = generateRandomNo(0, 5) + "%";
}
snowflakes[i].style.transition = "all " + generateRandomNo(5, 30) + "s";
snowflakes[i].style.WebkitTransition = "all " + generateRandomNo(5, 30) + "s";
}
}
Great, eh?
One more thing before I go...
Let's style the final signoff with... well,
signoff.
<p class="signoff">
Season's blessings,<br />
Your Chief Executive Officer
</p>
And here's the code. First, we align the text right.
p.signoff
{
text-align: right;
}
So the text is nicely aligned right, but there's something missing. A signature! We'll use this one. Save it in the
img folder. (No, that's not his
real signature. And no, I have no clue whose signature this is. Just looted it off a stock photo site.)
|
signature.jpg |
<p class="signoff">
Season's blessings,<br />
<img src="img/signature.jpg" height="150"/><br />
P. Smith<br />
Your Chief Executive Officer
</p>
And there, we've got a nicely signed letter!
That's it. Merry Christmas once again...
Enjoy your festive season!
Not your CEO,
T___T