Sunday 23 December 2018

Web Tutorial: A Christmas Letter from the CEO.

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

No comments:

Post a Comment