Tutorial- CSS3 Transforms

Page 1

A Tutorial: NextWeb- Animated clock and flip calendar using CSS3 Transforms Sandro Alberti; salberti@siggraph.org If you like this, please help us support the promotion of computer graphics and interactivity:

SETUP Hardware/software: You'll need a laptop/tablet, preferably with an HTML editor (Adobe Dreamweaver, MS Visual Studio, ...) or just a simple text editor will do. Files: Folder called 'start' and included files; save this on your Desktop. Download the files in ZIP format Materials: None. INTRO JavaScript performance, while massively improved in recent browser releases, can't ever compete with native browser-rendered effects. Luckily, the latest version of the CSS specification allows for direct rendering of common animations (including transformations like translate, rotate, or scale). In this tutorial, we'll create an animation for a clock and a calendar, using mainly CSS3. We'll also use a bit of JavaScript, but purely to grab the time and date necessary to set up the animation. See the final project here First, look at the image assets that you'll be working with: • • •

The background: wallpaper.png The clock face: clockface.png Clock hands for hour, minute, and second: hours.png minutes.png seconds.png

Note that there are no images for the calendar, since it will be rendered entirely with CSS. Open index.html; this is your basic starting-point code. The basic structure consists of a <div> for the clock face (and 3 <divs> inside of it, for the hands). And the calendar body, with 3 sections inside of it: the top, bottom, and the flipping part. You also have a stylesheet (currently blank other than what is needed to display the background and basic clock and calendar): styles/screen.css


And 3 scripts: • The standard JQuery script, so you can use JQuery in your page. • html5.js: A standard script to enable HTML5 elements in IE. It includes the popular html5shiv (to recognize and style HTML5 elements such as <article> <aside> <figure>...) and iepp (to allow IE to print these correctly on paper). • clocks.js: Your simple script page, where you'll write code to grab the initial time and date for the clock and calendar. TEST 1 The basic concept of a CSS3 Transformation is that you can tweak a page element (rotate, scale, move, etc). Add the CSS code below to the hourhand style, in order to rotate it to point to the 3 on the clock: .hourhand { -webkit-transform: rotate(90deg); -moz-transform: rotate(90deg); -o-transform: rotate(90deg); -ms-transform: rotate(90deg); transform: rotate(90deg); }

Yes, it's a lot of code, but that's basically because we need to target different browsers separately. TEST2 You can combine CSS3 Transformations with time intervals, to create CSS3 animations (Transitions). Try adding this code to the secondhand: (note, in all of the following examples, the code in red is already in your stylesheet) .secondhand { width: 300px; height: 300px; position: absolute; top: 0; left: 0; -webkit-transition: all 60s linear; -moz-transition: all 60s linear; -o-transition: all 60s linear; -ms-transition: all 60s linear; transition: all 60s linear; } #clock:target .secondhand { -webkit-transform: rotate(360deg); -moz-transform: rotate(360deg); -o-transform: rotate(360deg); -ms-transform: rotate(360deg); transform: rotate(360deg); }


You'll notice that the second part looks just like what we did with the hour hand above (except it's being targeted for when the page loads with #clock in the URL): we'll rotate the second hand (and in this case the rotation is one full circle, 360 degrees). Meanwhile the secondhand's style is 'transitioning': affecting all properties of the element, over a period of 60 seconds, in a linear timing function. So whenever the secondhand is updated (when it gets targeted), it will apply any styles (360-degree rotation) based on an animation defined by the 'transition' styles. To try this out, just load the page with #clock added to the end of the URL. STEP 1 Now it's time to get started with a real clock, that keeps real time. First, create the transitions that move each clock hand at the correct rate. Remember, CSS3 Transitions are measured in seconds, so one revolution of the minutehand takes 60 seconds times 60, which is 3600 seconds. And for the hourhand it's 3600 seconds times 12, or 432,000 seconds. The following code will take care of rotating each hand 360 degrees, and linked to an animation just like the one you tested earlier: affecting all properties of the element, over a period of 60 seconds, in a linear timing function. (notice that the animations will start when #clock has a class of .running, which will later be added with JQuery) .hourhand { width:300px; height:300px; position:absolute; top:0; left:0; -webkit-transition: all 43200s linear; -moz-transition: all 43200s linear; -o-transition: all 43200s linear; -ms-transition: all 43200s linear; transition: all 43200s linear; } .minutehand { width: 300px; height: 300px; position: absolute; top: 0; left: 0; -webkit-transition: all 3600s linear; -moz-transition: all 3600s linear; -o-transition: all 3600s linear; -ms-transition: all 3600s linear; transition: all 3600s linear; }


.secondhand { width: 300px; height: 300px; position: absolute; top: 0; left: 0; -webkit-transition: all 60s linear; -moz-transition: all 60s linear; -o-transition: all 60s linear; -ms-transition: all 60s linear; transition: all 60s linear; } #clock.running .secondhand { -webkit-transform: rotate(360deg); -moz-transform: rotate(360deg); -o-transform: rotate(360deg); -ms-transform: rotate(360deg); transform: rotate(360deg); } #clock.running .minutehand { -webkit-transform: rotate(360deg); -moz-transform: rotate(360deg); -o-transform: rotate(360deg); -ms-transform: rotate(360deg); transform: rotate(360deg); } #clock.running .hourhand { -webkit-transform: rotate(360deg); -moz-transform: rotate(360deg); -o-transform: rotate(360deg); transform: rotate(360deg); }

PART 2 So far so good, but... the secondhand stops after just one second, and the minutehand stops after only one minute, and the hourhand (if you waited long enough to see it) stops after one hour. This can be resolved by rotating more revolutions (more than 360 degrees). If you want it all to run for one hour (most people won't sit on a Web page for that long), set the seconds to 3600 revolutions (1,296,000 degrees), and set the minutes to 60 revolutions (21,600 degrees). And of course, you also have to update the time it takes the secondhand and minute hand to complete the larger number of revolutions (60 x 3600 seconds for the secondhand, and 3600 x 60 seconds for the minutehand): .minutehand { width:300px; height:300px; position:absolute; top:0; left:0; -webkit-transition: all 216000s linear;


-moz-transition: all 2160000s linear; -o-transition: all 216000s linear; -ms-transition: all 216000s linear; transition: all 216000s linear; } .secondhand { width:300px; height:300px; position:absolute; top:0; left:0; -webkit-transition: all 216000s linear; -moz-transition: all 216000s linear; -o-transition: all 216000s linear; -ms-transition: all 216000s linear; transition: all 216000s linear; } #clock.running .secondhand { -webkit-transform: rotate(1296000deg); -moz-transform: rotate(1296000deg); -o-transform: rotate(1296000deg); -ms-transform: rotate(1296000deg); transform: rotate(1296000deg); } #clock.running .minutehand { -webkit-transform: rotate(21600deg); -moz-transform: rotate(21600deg); -o-transform: rotate(21600deg); -ms-transform: rotate(21600deg); transform: rotate(21600deg); }

PART 3 We need to set the correct time when the page loads. Since CSS can't do this, we'll use JavaScript. First, a function sets the variables that will hold the time: s (seconds), m (minutes), h (hours). And the number of degrees that the minutehand/secondhand moves each minute/second (mdelta=6) and the number of degrees the hourhand moves each hour (hdelta=30; and an additional fraction of an hour, based on minutes: (m/60)*30). function setTime() { // Get the current date and time d = new Date(); // Get the hours h = d.getHours(); if(h > 12) h = h - 12; // Get the minutes


m = d.getMinutes(); // Get the seconds s = d.getSeconds(); // How much does each second, minute or hour represent in degrees? mdelta = 6; // 360 degrees divided by 60 mins/secs = 6 degrees hdelta = 30; // 360 degrees divided by 12 hours = 30 degrees // The hour hand should have an extra number of degrees for the minutes hextra = (m/60)*30; }

Then, we use these to create the same CSS3 Transforms and Transitions that we saw before (except this is done only once, through JQuery, to set the correct initial position of the clock) function setTime() { // Get the current date and time d = new Date(); // Get the hours h = d.getHours(); if(h > 12) h = h - 12; // Get the minutes m = d.getMinutes(); // Get the seconds s = d.getSeconds(); // How much does each second, minute or hour represent in degrees? mdelta = 6; // 360 degrees divided by 60 mins/secs = 6 degrees hdelta = 30; // 360 degrees divided by 12 hours = 30 degrees // The hour hand should have an extra number of degrees for the minutes hextra = (m/60)*30; // NOTE: we don't rotate the div here - which the transition is applied to $('.secondhand img').css({webkitTransform: 'rotate('+mdelta*s+'deg)',MozTransform: 'rotate('+mdelta*s+'deg)',OTransform: 'rotate('+mdelta*s+'deg)',transform: 'rotate('+mdelta*s+'deg)'}); $('.minutehand img').css({webkitTransform: 'rotate('+mdelta*m+'deg)',MozTransform: 'rotate('+mdelta*m+'deg)',OTransform: 'rotate('+mdelta*m+'deg)',transform: 'rotate('+mdelta*m+'deg)'}); $('.hourhand img').css({webkitTransform: 'rotate('+((hdelta*h)+hextra)+'deg)',OTransform: 'rotate('+((hdelta*h)+hextra)+'deg)',MozTransform: 'rotate('+((hdelta*h)+hextra)+'deg)',transform: 'rotate('+((hdelta*h)+hextra)+'deg)'}); }


Finally, we run this function when the page loads: (and also add a class .running to #clock, which, as we saw earlier, is what runs the animation for everything inside the #clock <div>) $(document).ready(function(){ setTime(); $("#clock").addClass("running"); });

Since IE9 supports CSS3 Transforms, but does not support Transitions, you can fake it by calling the JQuery function every minute (constantly resetting the Transform positions of the hands, based on the time): $(document).ready(function(){ setTime(); $("#clock").addClass("running"); if ($.browser.msie) { t = setInterval(“setTime()�,1000); } });

PART 4 Now it's time to build the flipping calendar. Here we'll use special CSS3 Transforms called '3d Transforms'. These offer 3d distortion effects, but only work on Webkit browsers. So in the end you'll see an animation in all modern browsers, but will only get the full effect on Chrome and Safari. The basic calendar is all set up already, including a general calendar zone, a top part, a bottom part, and a flip part that sits at the top until it flips as part of the animation. For the calendar, you'll need 2 different kinds of animations, because, as the calendar flips over, the date should change, and we also want to use a 3d transformation about the X axis to get the right effect. Add the code below: (notice that we have 2 animations: .fliptop and .flipbottom; these 2 classes will be injected into the page with JavaScript, a bit later) .fliptop { -webkit-transform: rotate(90deg); -moz-transform: rotate(90deg); -o-transform: rotate(90deg); -ms-transform: rotate(90deg); transform: rotate(90deg); } .flipbottom { bottom:2px; -webkit-transform: rotate(180deg); -moz-transform: rotate(180deg); -o-transform: rotate(180deg); -ms-transform: rotate(180deg); transform: rotate(180deg); }


.flipbottom .calendar-month, .flipbottom .calendar-day { -webkit-transform: rotate(180deg); -moz-transform: rotate(180deg); -o-transform: rotate(180deg); -ms-transform: rotate(180deg); transform: rotate(180deg); } .calendar-flip { position:absolute; top:6px; left:6px; -webkit-transition: all 0.1s ease-in-out; -moz-transition: all 0.1s ease-in-out; -o-transition: all 0.1s ease-in-out; -ms-transition: all 0.1s ease-in-out; transition: all 0.1s ease-in-out; -webkit-transform-origin: 50% 100%; -moz-transform-origin: 50% 100%; -o-transform-origin: 50% 100%; -ms-transform-origin: 50% 100%; transform-origin: 50% 100%; }

PART 5 To trigger the calendar animation, and inject a set of months and days, we'll need JavaScript, consisting of: 1. Verify if we are showing current month/day; otherwise increment by one. 2. When the calendar gets to the right date, start running the clock- and take care of the IE clock fix; so you can remove these from the document.ready() function: $("#clock").addClass("running"); if ($.browser.msie) { t = setInterval(“setTime()�,1000); }

3. Set the 1st part of the animation. 4. Run the 2nd part of the animation. $(document).ready(function(){ setTime(); months = new Array("JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"); day = 1 month = 0; shownday = 1; shownmonth = 0; var t; // setInterval variable function flipcalendar() { doanimation = false; setTime(); if (month>shownmonth) { doanimation = true;


shownmonth = shownmonth+1; } else { $(".calendar-flip .calendar-month").css({visibility:"hidden"}); } if (day>shownday){ doanimation = true; shownday = shownday+1; } else { $(".calendar-flip .calendar-day").css({visibility:"hidden"}); } if (!doanimation) { // We've arrived at the right date, so... // Set the time, and set the clock running $("#clock").addClass("running"); clearInterval(t); if ($.browser.msie) { t = setInterval("setTime()",1000); } return false; } // set the top part of the calendar to the new month and/or day $(".calendar-top .calendar-month").text(months[shownmonth]); $(".calendar-top .calendar-day").text(shownday); // Add the class to trigger part 1 of the animation $(".calendar-flip").addClass("fliptop"); // Add a delay before firing the following code - this is a bit of a hack $(".calendar-flip .calendar-month").animate({opacity:1},100,function(){ // We’re now half way through the animation // Change the position to allow for the central gap $(".calendar-flip").css({top:8}); // Set the new month/day for the flip part $(".calendar-flip .calendar-month").text(months[shownmonth]); $(".calendar-flip .calendar-day").text(shownday); // Add the class to trigger the second part of the animation $(".calendar-flip").addClass("flipbottom"); // Another delay hack before resetting it all ready for the next time $(".calendar-flip").animate({opacity:1},200,function(){ // Set the bottom part to have the new month/day $(".calendar-bottom .calendar-month").text(months[shownmonth]); $(".calendar-bottom .calendar-day").text(shownday); // Hide the flip part and reset it all back to the top $(this).hide().css({top:6}).removeClass("fliptop").removeClass("flipbotto m").animate({top:6},200,function(){$(this).show();}); }) });


NEXT _


Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.