Tuesday 17 February 2015

Web Tutorial: Year of the Goat

May fortune befall you in the Year of the Goat!

Happy Lunar New Year!

It's The Lunar New Year, and I'm in a festive mood.

Did I mention that I used to design Flash greeting cards for such occasions, and sometimes even get paid for them? Well, my Flash days are over, but CSS3 is a close second!

I'll be showing you an animated greeting card I designed for this Lunar New Year. No images, minimal programming. 90% CSS3! The code listing is here. There's a LOT of CSS in there, and I don't feel like reproducing all of it here, since it can get rather repetitive. So for the purposes of this web tutorial, I'm going to assume you have the link open where you can refer to the code.

The code's also rather sloppy. I never intended for this to be a web tutorial, but I figured later, why the hell not? Just bear with me, a lot of stuff here is not what industry experts would consider "best practice". I also won't be going too much into detail. This is one of those web tutorials where the concept matters more than the execution.

Here's the beginning HTML and CSS:
<!DOCTYPE html>
<html>
    <head>
        <title>Yang</title>
        <meta charset="utf-8">
        <style type="text/css">
            #character_wrapper
            {
                width:500px;
                height:700px;
                margin:100px auto 0px auto;
            }

            .stroke_yang
            {
                position:absolute;
                width:0px;
                height:0px;
                -webkit-transition: width 0.5s, height 0.5s,-webkit-transform 0.5s;  /* For Safari 3.1 to 6.0 */
                transition: width 0.5s, height 0.5s, transform 0.5s;
                -webkit-transition-timing-function: ease-in-out; /* Safari and Chrome */
                transition-timing-function: ease-in-out;
            }

            .stroke_couplet
            {
                position:absolute;
            }

            .
            .
            .
            .
            (for the rest of the CSS code, click here)
            .
            .
            .
            .
            .
            .

            .boxframe
            {
                position:absolute;
                width:70px;
                height:70px;
                background-color:#FFDD00;
                border:5px solid #AA0000;
                color:#FF0000;
                font-size:65px;
                font-weight:bold;
                opacity: 0;
                filter: alpha(opacity=0); /* For IE8 and earlier */
                -webkit-transition: all 4s;  /* For Safari 3.1 to 6.0 */
                transition: all 4s;
                -webkit-transition-timing-function: ease-in-out; /* Safari and Chrome */
                transition-timing-function: ease-in-out;
            }

            .boxframe_rotate
            {
                -webkit-transform: rotateY(360deg); /* Chrome, Safari, Opera */
                transform: rotateY(360deg);
                opacity: 1;
                filter: alpha(opacity=100); /* For IE8 and earlier */
            }
        </style>

    </head>

    <body>
        <div id="character_wrapper">
            <div id="stroke0a" class="stroke_yang"></div>
            <div id="stroke0b" class="stroke_yang"></div>   
            <div id="stroke1" class="stroke_yang"></div>   
            <div id="stroke2" class="stroke_yang"></div>
            <div id="stroke3" class="stroke_yang"></div>
            <div id="stroke4" class="stroke_yang"></div>   

            <div id="box1" class="boxframe">       
                <div id="gong_stroke1" class="stroke_couplet"></div>
                <div id="gong_stroke2" class="stroke_couplet"></div>
                <div id="gong_stroke3" class="stroke_couplet"></div>
                <div id="gong_stroke4" class="stroke_couplet"></div>
                <div id="gong_stroke5" class="stroke_couplet"></div>
                <div id="gong_stroke6" class="stroke_couplet"></div>
                <div id="gong_stroke7" class="stroke_couplet"></div>
                <div id="gong_stroke8" class="stroke_couplet"></div>
                <div id="gong_stroke9" class="stroke_couplet"></div>
                <div id="gong_stroke10" class="stroke_couplet"></div>
            </div>
            <div id="box2" class="boxframe">
                <div id="xi_stroke1" class="stroke_couplet"></div>
                <div id="xi_stroke2" class="stroke_couplet"></div>
                <div id="xi_stroke3" class="stroke_couplet"></div>
                <div id="xi_stroke4" class="stroke_couplet"></div>
                <div id="xi_stroke5" class="stroke_couplet"></div>
                <div id="xi_stroke6" class="stroke_couplet"></div>
                <div id="xi_stroke7" class="stroke_couplet"></div>
                <div id="xi_stroke8" class="stroke_couplet"></div>
                <div id="xi_stroke9" class="stroke_couplet"></div>
                <div id="xi_stroke10" class="stroke_couplet"></div>
                <div id="xi_stroke11" class="stroke_couplet"></div>
                <div id="xi_stroke12" class="stroke_couplet"></div>
            </div>
            <div id="box3" class="boxframe">
                <div id="fa_stroke1" class="stroke_couplet"></div>
                <div id="fa_stroke2" class="stroke_couplet"></div>
                <div id="fa_stroke3" class="stroke_couplet"></div>
                <div id="fa_stroke4" class="stroke_couplet"></div>
                <div id="fa_stroke5" class="stroke_couplet"></div>
                <div id="fa_stroke6" class="stroke_couplet"></div>
                <div id="fa_stroke7" class="stroke_couplet"></div>
            </div>
            <div id="box4" class="boxframe">
                <div id="cai_stroke1" class="stroke_couplet"></div>
                <div id="cai_stroke2" class="stroke_couplet"></div>
                <div id="cai_stroke3" class="stroke_couplet"></div>
                <div id="cai_stroke4" class="stroke_couplet"></div>
                <div id="cai_stroke5" class="stroke_couplet"></div>
                <div id="cai_stroke6" class="stroke_couplet"></div>
                <div id="cai_stroke7" class="stroke_couplet"></div>
            </div>
        </div>   
    </body>
</html>


What the CSS does

The character_wrapper element simply holds everything together where I want it, which is somewhere middle of the screen.

The Calligraphy

The Yang character is rendered in red. I used the egg shape from this link and adjusted the box-shadow (and sometimes the transform) property to shape individual strokes. But all the strokes have something in common, thus the stroke_yang class. You'll notice that the width and height properties of each individual stroke are set to 0px, which makes them effectively invisible. That's because we'll be animating them later.

The position property is set to "absolute", because the strokes need adjusting here and there, and setting them to "relative" would mean that if I adjust stroke 1, I have to redo a whole lot of adjustment to strokes 2,3 4, etc. The transition properties are also set for maximum awesomeness.

The Gong, Xi, Fa and Cai characters are in black, and encased in small colored squares.  The CSS for each stroke (the stroke_couplet class) means...

position: absolute for easier adjustment later on. And that's no small thing, considering how many different strokes each character has!

The CSS for each square (the boxframe class) means...

position: absolute for easier adjustment later on.
width, height set to 70px to form a square.
border has been set to 5px so each box has a frame.
opacity has been set to 0 so that it's invisible at the start. We'll be animating this later.

There's a lot more CSS for individual character strokes, and the like. They're in the code listing. But for the purpose of this web tutorial, we're not going to get into those.

Now for the JavaScript!

Basically, in this code, I animate the four boxes containing the Gong, Xi, Fa and Cai characters.

        <script>
        function writeword()
        {
            document.getElementById("box1").className="boxframe boxframe_rotate";
            document.getElementById("box2").className="boxframe boxframe_rotate";
            document.getElementById("box3").className="boxframe boxframe_rotate";
            document.getElementById("box4").className="boxframe boxframe_rotate";
        }
        </script>


Then I set the width and height properties for each stroke in the Yang character, and the times they would be "written".

        <script>
        function writeword()
        {
            document.getElementById("stroke0a").style.width="40px";document.getElementById("stroke0a").style.height="80px";
            document.getElementById("stroke0b").style.width="20px";document.getElementById("stroke0b").style.height="60px";
            document.getElementById("stroke1").style.width="100px";document.getElementById("stroke1").style.height="20px";
            document.getElementById("stroke2").style.width="80px";document.getElementById("stroke2").style.height="10px";
            document.getElementById("stroke3").style.width="120px";document.getElementById("stroke3").style.height="20px";
            document.getElementById("stroke4").style.width="20px";document.getElementById("stroke4").style.height="200px";
            document.getElementById("box1").className="boxframe boxframe_rotate";
            document.getElementById("box2").className="boxframe boxframe_rotate";
            document.getElementById("box3").className="boxframe boxframe_rotate";
            document.getElementById("box4").className="boxframe boxframe_rotate";
        }
        </script>


Replaying the card

So now we have a nifty greeting card. But it'll be a pity if we could only play it once. So I created a Replay button. I took the lazy way out, and just added the button to the HTML, like this:
<body onload="writeword();">
        <input type="button" value="click here for T___T's Lunar New Year message!" onclick="location.reload();">

This basically means the page will reload when the button is clicked. And since I added onload="writeword();" to the body tag, the animation will start when the page is loaded or reloaded. Yes, the proper way would be to reverse the changes I made to the properties in the writeword() function... but what the hell, it's the festive season and I really can't be arsed. This works just as well for our purposes.

It works. Click it, try it!



And the beauty of this is - it's all HTML, CSS and JavaScript. No clunky images to deal with. Sleek and elegant!

Don't be afraid to experiment! You're only Yang once!
T___T

No comments:

Post a Comment