Wednesday, 1 April 2015

Web Tutorial: The Faux 3D Easter Egg (Part 1/2)

Happy April Fool's Day! Easter approaches. The sweet smell of renewal fills the air. And with it, I bring you more CSS3 goodness. I present... the spinning Easter Egg.

What's so special about that?

The animations in play today aren't anything you haven't seen before. But everything will be in 3D.

Really?!

No, not really. You see, back in the day where graphic processors and browsers weren't so advanced, we had to do decent approximations of this kind of thing. That's right, we're going to fake it. It is, after all, April Fool's Day! This is something I used to do in Flash, and now it can be done on CSS3! I'll show you all the different components I put together to create this effect, and the logic behind it.

This is more about concept today, so we're not going to obsess over the correct usage of CSS.

First, set up the HTML. We're going to draw an egg.
<!DOCTYPE html>
<html>
    <head>
        <title>Easter</title>
    </head>

    <body>
        <div class="egg">

        </div>
    </body>
</html>

Now, let's create the CSS class egg. For reference, check this link. (https://css-tricks.com/examples/ShapesOfCSS/). I'm just copying and pasting snippets of CSS code for the egg shape because I'm such a lazy bastard programming genius.
<!DOCTYPE html>
<html>
    <head>
        <title>Easter</title>

        <style type="text/css">
            .egg
            {
                background-color:#dddddd;
                -webkit-border-radius: 63px 63px 63px 63px / 108px 108px 72px 72px;
                border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%;
                width:200px;
                height:300px;
                margin:0 auto 0 auto;
            }
        </style>

    </head>

    <body>
        <div class="egg">

        </div>
    </body>
</html>

The egg doesn't need a border. But we'll give it one anyway, just to have a visual point of reference. This egg has a grey background specified for your visual reference, and we'll remove it when the time is right.. margin:0 auto 0 auto sets the egg to appear dead center of the screen.

This is what it should look like so far.


Doesn't look like much!


Don't worry. It will, once we start animating! For that, we need a nice Easter Egg pattern. I'm going to just add a nested div inside the first div.
        <div class="egg">
            <div id="eggpattern" class="pattern_wrapper">
                <div class="patterns">
                    <div class="pattern_wrapper">
                        <div class="pattern pattern1">
                           
                        </div>
                        <div class="pattern pattern2">
                           
                        </div>
                        <div class="pattern pattern3">
                           
                        </div>
                    </div>
                </div>
            </div>

        </div>


The eggpattern div holds all the blings you're going to subject this poor innocent egg to. This will be important later on. For now, add the following styles to your CSS.
            .pattern_wrapper
            {
                width:800px;
                height:300px;
                border:1px solid #FF0000;
            }

            .patterns
            {
                width:200px;
                height:300px;
                overflow:hidden;
                position:relative;
                float:left;

                border:1px solid #000000;            
            }

            .pattern
            {
                position:absolute;
                width:200px;
                height:300px;
                margin-left:0px;
                margin-top:0px;
                overflow:hidden;
            }

            .pattern1
            {
                z-index:10;
                background-color:#FFFF00;
            }

            .pattern1:before
            {
                content:"";
                display:block;
                background-color:#FFAA99;
                width:200px;
                height:200px;
                margin-top:-100px;
            }

            .pattern2
            {
                z-index:20;
            }

            .pattern2:before
            {
                content:": :";
                font-size:120px;
                color:#FF5555;
                display:block;
                position:absolute;
                transform:rotate(45deg);
                margin-top:80px;
                margin-left:20px;
            }

            .pattern2:after
            {
                content:":";
                font-size:240px;
                color:#FF5555;
                display:block;
                position:absolute;
                transform:rotate(5deg);
                margin-top:-80px;
                margin-left:100px;
            }

            .pattern3
            {
                z-index:30;
            }

            .pattern3:before
            {
                content:"";
                display:block;
                width:80px;
                height:150px;
                -webkit-border-radius: 63px 63px 63px 63px / 108px 108px 72px 72px;
                border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%;
                box-shadow: -10px -15px 0 0px #FF8800;
                margin-left:20px;
                margin-top:20px;
                -ms-transform: rotate(-20deg); /* IE 9 */
                -webkit-transform: rotate(-20deg); /* Chrome, Safari, Opera */
            }

            .pattern3:after
            {
                content:"";
                display:block;
                width:80px;
                height:150px;
                -webkit-border-radius: 63px 63px 63px 63px / 108px 108px 72px 72px;
                border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%;
                box-shadow: 5px 10px 0 10px #FF8800;
                margin-left:50px;
                margin-top:-20px;
                -ms-transform: rotate(-20deg); /* IE 9 */
                -webkit-transform: rotate(-20deg); /* Chrome, Safari, Opera */
            }


The patterns (plural) class is for the div that holds the eggpattern div, like a sheath. And outlined in black for your visual reference.

The pattern_wrapper class is for the eggpattern div that holds all the different pattern blocks. It's also the div that will be animated later. Here I've given it a red border, again, for your visual reference.

The pattern (singular) class has its position property set to absolute because these are going to be overlaid on top of each other. The pattern1 class, with z-index set to 10, is behind pattern2 and pattern3.

If all this is gibberish to you, don't worry too much about it. It's tangential to what we're really doing here today. Let's see what we just did:


See that big block of garish color? That's all the patterns we fit into each pattern block. You'll notice that the eggpattern div is four times as long as the pattern block. That's no coincidence, because we're doing to fill this space up as well.

What we just did was the front of the egg. Now we do the back of the egg. Add these nested divs to your collection!
        <div class="egg">
            <div id="eggpattern" class="pattern_wrapper">
                <div class="patterns">
                    <div class="pattern_wrapper">
                        <div class="pattern pattern1">
                           
                        </div>
                        <div class="pattern pattern2">
                           
                        </div>
                        <div class="pattern pattern3">
                           
                        </div>
                    </div>
                    <div class="pattern_wrapper">
                        <div class="pattern pattern1">
                           
                        </div>
                        <div class="pattern pattern2a">
                           
                        </div>
                        <div class="pattern pattern3a">
                           
                        </div>
                    </div>
                    <div class="pattern_wrapper">
                        <div class="pattern pattern1">
                           
                        </div>
                        <div class="pattern pattern2">
                           
                        </div>
                        <div class="pattern pattern3">
                           
                        </div>
                    </div>
                    <div class="pattern_wrapper">
                        <div class="pattern pattern1">
                           
                        </div>
                        <div class="pattern pattern2a">
                           
                        </div>
                        <div class="pattern pattern3a">
                           
                        </div>
                    </div>

                </div>
            </div>
        </div>


Make these changes to the CSS
            .pattern2,.pattern2a
            {
                z-index:20;
            }

            .pattern3,.pattern3a
            {
                z-index:30;
            }


            .pattern2a:before
            {
                content:". .:";
                font-size:150px;
                color:#FF5555;
                display:block;
                position:absolute;
                transform:rotate(55deg);
                margin-top:50px;
                margin-left:20px;
            }

            .pattern2a:after
            {
                content:":";
                font-size:270px;
                color:#FF5555;
                display:block;
                position:absolute;
                transform:rotate(-45deg);
                margin-top:-80px;
                margin-left:50px;
            }

            .pattern3a:before
            {
                content:"";
                display:block;
                width:80px;
                height:100px;
                -webkit-border-radius: 63px 63px 63px 63px / 108px 108px 72px 72px;
                border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%;
                box-shadow: 10px -10px 0 0px #DD00FF;
                margin-left:60px;
                margin-top:20px;
                -ms-transform: rotate(120deg); /* IE 9 */
                -webkit-transform: rotate(120deg); /* Chrome, Safari, Opera */
            }

            .pattern3a:after
            {
                content:"";
                display:block;
                width:80px;
                height:180px;
               -webkit-border-radius: 63px 63px 63px 63px / 108px 108px 72px 72px;
                border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%;
                box-shadow: -10px 10px 0 10px #DD00FF;
                margin-left:50px;
                margin-top:-20px;
                -ms-transform: rotate(-80deg); /* IE 9 */
                -webkit-transform: rotate(-80deg); /* Chrome, Safari, Opera */
            }


Now look at the result. Back and front of the egg are lined up one after another. The pattern1 class makes it seamless. Feel free to go wild with the colors and stuff. The specifications I provided were just examples.

Now, set the border property of the pattern_wrapper and patterns classes class to 0px, like so.
            .pattern_wrapper
            {
                width:800px;
                height:300px;
                border:0px solid #FF0000;
            }

            .patterns
            {
                width:200px;
                height:300px;
                overflow:hidden;
                position:relative;
                float:left;
                border:0px solid #000000;           
            }


Looking better.



Now, we're going to specify the animations that make the egg spin left or right. Add these classes to your CSS.
            .spin_left
            {
                -webkit-animation: spinleft 2s linear infinite; /* Chrome, Safari, Opera */
                animation: spinleft 2s linear infinite;
            }

            /* Chrome, Safari, Opera */
            @-webkit-keyframes spinleft
            {
                from {margin-left: 0px;}
                to {margin-left: -400px;}
            }

            /* Standard syntax */
            @keyframes spinleft
            {
                from {margin-left: 0px;}
                to {margin-left: -400px;}
            }

            .spin_right
            {
                -webkit-animation: spinright 2s linear infinite; /* Chrome, Safari, Opera */
                animation: spinright 2s linear infinite;
            }

            /* Chrome, Safari, Opera */
            @-webkit-keyframes spinright
            {
                from {margin-left: -400px;}
                to {margin-left: 0px;}
            }

            /* Standard syntax */
            @keyframes spinright
            {
                from {margin-left: -400px;}
                to {margin-left: 0px;}
            }


For more on CSS animations, click here. (http://www.w3schools.com/css/css3_animations.asp)

What we did was to specify that when "spinning" left, we actually just change the margin-left property. And vice versa for spinning right. The animations are set to infinite, and will graduate over 2 seconds. Adjust this value if you want the egg to spin faster or slower.

Alter the class of the eggpattern div like so:
<div id="eggpattern" class="pattern_wrapper spin_left">


Refresh your browser. Now you'll see the patterns move left, and repeat indefinitely! But we're not done! Add one more line to the CSS class egg.
            .egg
            {
                background-color:#dddddd;
                -webkit-border-radius: 63px 63px 63px 63px / 108px 108px 72px 72px;
                border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%;
                width:200px;
                height:300px;
                margin:0 auto 0 auto;
                overflow:hidden;
            }


Presto! Because the part of the pattern that is outside of the egg is now set to hidden, it looks like the egg is spinning! Much better, eh? The Easter Bunny would be proud.


Since we already made an animation specification for "spinning" right, let's not waste it. Create two buttons in your HTML, just after the egg div, like so:

        </div>
        <input type="button" value="<" onclick="spin_left();">
        <input type="button" value=">" onclick="spin_right();">

</html>


And add this JavaScript to your HTML head.
        <script>
            function spin_left()
            {
                var egg=document.getElementById("eggpattern");
                egg.className="pattern_wrapper spin_left";
            }

            function spin_right()
            {
                var egg=document.getElementById("eggpattern");
                egg.className="pattern_wrapper spin_right";
            }
        </script>


Now by default, the egg spins left. But you can change the direction anytime by clicking on the buttons. The JavaScript functions basically change the CSS class of the eggpattern div to animate in the direction specified by the CSS classes spin_right and spin_left.


So far so good! We have a nicely decorated (OK, that one's subjective, but whatevs, dude) Easter egg that spins left and right at the click of a button. But damn, it does look kind of flat, doesn't it? We're going to fix that, no worry.

Next

Applying more CSS tricks to bring the 3D effect to life! Stay tuned!

No comments:

Post a Comment