Tuesday, April 24, 2012

Presentation: The Modern Web, Part 3: Social Networking

Today I gave a public Neudesic webcast, The Modern Web, Part 3: Social Networking. Below is the presentation from the webcast. The webcast recording should also be available soon at neudesic.com .

Monday, April 23, 2012

Adventures in Windows 8: Task Board, Part 1: An HTML5-JavaScript Metro App

I had an opportunity today to demo a Windows 8 Metro app at the Windows 8 Developer event in LA along with my Neudesic colleague Mickey Williams. I’ll describe here in Part 1 the demo app, Task Board, and in subsequent parts we’ll explore how it was built. Task Board is not a fully completed application, but its well along and is the result of only 3 days’ work—a testimony to how quickly you can get proficient at Metro app development. This is also not what I would call a very sophisticated Metro app – in fact it’s my second Metro app ever, and I’m still learning the ropes.

One of the things you notice with tablets today is that while they are really popular, most people use them to consume content (books, video), browse the web, or interact with business-to-consumer apps. There aren’t all that many examples of productivity apps or business apps on tablets yet. This is where I think Windows 8 and Metro have an opportunity to really shine: you’ll be able to get actual work done on Windows 8 tablets.
To have something decent to demo, I decided to create a new Metro application. I chose a task board application, in which you can put “cards on a wall” as an aid in project management. Each card represents a task. A task board is a useful visual aid in project team meetings where you can move cards around and consider "what if's".
Let's take a walk-through of the application.


Tile and Splash Screen

Like all Metro apps, Task Board has a tile in the Start screen. It’s not a “live tile” yet in that the application doesn’t pass any notification information up to the tile, but that’s a behavior that could be added in the future.  

Touching or clicking the tile launches Task Board, which briefly displays this splash screen:

Both the tile and splash screen are simple PNG bitmap images. There are 4 images in all, named logo.png, smalllogo.png, storelogo.png, and splash.png.

Views and Navigation
Task Board has two views (with more to come): Task Board and Rock Wall. Navigation between the views is accomplished with two simple links at top. Down the road you may see this become sections that you can horizontally slide between.

Additional views we’re likely to add in the future might also include an expense view and a workload-per-team member view.
 

Task Board View
Task Board view is the “cards on a wall” surface on which you can drag around cards. Dragging is a good interface for touch devices, but we’ve been careful to make the experience equally good for mouse and keyboard users as well. If you touch or click on a card’s border or task number, it will be selected (indicated with a thick border). If cards overlap, selecting a card brings it topmost.


The cards have fields for title, description, who, hours, and status (to do, in progress, to verify, or completed). The status field controls the card color. A task number is displayed at upper right.

To create a task card, or remove a selected task card, you use the left-side commands on the App Bar. You can bring the App Bar into view by swiping from the top or bottom of the screen; or via the shortcut key Windows + Z. Other App Bar commands include Remove All, which deletes all task cards; and Arrange, which nicely arranges the cards with a smooth animation where they glide into place.


The App Bar is typically shown on the bottom of applications, but I thought it worked better at top in this case. If you find yourself using the App Bar a lot, which you might when heavily editing tasks, you can pin it in place.


Rock Wall View
The Rock Wall is a view of the tasks in terms of size, where tasks are rendered as boulders, rocks, and stones based on the number of hours. Up to 8 hours is a pebble, up to 40 hours is a rock, and anything larger is a boulder. The rocks fall into place in a nice bounce animation.



Background
The default background is a green board, but there are other choices. There’s a drop-down in the App Bar that lets you select other background images or background colors. Below is the “Wood” theme.


Storage
The commands at the right of the App Bar allow new projects to be created, existing projects to be opened, and projects to be saved. There’s also a Sample button which loads a sample project of tasks, making it easy for the application to be demoed.


There’s some additional work to be done here on storage, including project naming and file browsing. What I have in mind is the device/cloud model, as you may have seen in apps like the latest Kindle app for iPad. The idea is your central storage is in the cloud (thus freeing you to change devices whenever you want to), but you can work with the data locally on your device if you choose to. Not in place yet, but coming. This is part of the “personal cloud” concept that I am very much a believer in.

Development Approach
You can develop Metro apps 3 ways: in C++/Xaml, in .NET/Xaml, or in HTML5-JavaScript. I can work in all three, but since I’m investing a lot of time these days in HTML5/JavaScript that was a natural choice for me. Although WinRT (the Windows runtime) is careful to treat all three development approaches as equal-class citizens, there is an advantage I think to the HTML5/JavaScript approach in that you can leverage the mammoth amount of open source libraries that are out there for the web such as jQuery and many others.

This gives you an overview of the application. In Part 2, we’ll take a look at the internals. Stay tuned!

Monday, April 16, 2012

Outside-the-Box Pizza, Part 4: Social Integration with Twitter


In this series, we’re looking at Outside-the-Box Pizza, a web-mobile-social-cloud demo, from a variety of perspectives that include design, technologies, and techniques. The online demo is at http://outsidetheboxpizza.com. Here in Part 4, we’ll be looking at the social experience which in this app revolves around the use of Twitter.  We’ll look at three things:

• Social Media Strategy
• Gamification in the Online Experience
• Twitter Integration with @Anywhere


Social Media Strategy: “Pizza as Individual as You Are”

Outside-the-Box Pizza knows the power of the mobile and social phenomenon, and has crafted their company around appealing to the young, hip crowd who live the digital lifestyle. From Day 1, their strategy has been emphasizing the uniqueness and creativity of individuals. That’s why they have the name they do, and it’s why they provide some very unusual pizza toppings (like elk and mashed potato), shapes (square, heart), and sauces (BBQ, chocolate). This fits very well with today’s ever-growing mobile-and-social communities. Their tag line is, “Pizza as individual as you are”.


Outside-the-Box Pizza is savvy about modern online marketing and is very much aware of the important role social media plays in keeping an ongoing relationship with new and existing customers (see Flip the Funnel by Joseph Jaffe for more on that).

There are many ways to integrate with social networks: you can view/search content, post content, and allow sign-in with social identities. There are also many social networks to choose from. Outside-the-Box Pizza has chosen to focus their efforts around Twitter, where clients will tweet about unusual pizzas. Outside-the-Box Pizza will tweet as well.


Gamification in the Online Experience

Outside-the-Box Pizza is also very aware of the gamification phenomenon, in which adding a fun, compelling, and competitive element to an experience builds customer loyalty and increases return visits.

When a customer orders a unique pizza, Outside-the-Box Pizza wants them to tweet about it. On the Tweetza Pizza page, clients can see the twitter feed for #outsideboxpizza and, if they wish, sign in with a Twitter id and add their own tweets. Of course, they can also do this directly via Twitter itself, but there’s value in integrating it with the application. 


It isn’t necessary for users to identify themselves to view the Twitter feed, but in order to send tweets they do need to sign in. Clicking on the Connect with Twitter button brings up a Twitter sign-in dialog.

To promote the most interesting pizzas, Outside-the-Box Pizza has a section of the site called Cool Pizzas which is manually curated by an editor.



Twitter Integration with Twitter @Anywhere

Social network integration is possible from the front-end or the back-end of a web application. In this case, Outside-the-Box Pizza uses front-end integration. That is, all of the integration work is being done in the HTML/JavaScript layer that runs in the web browser. Twitter provides an easy-to-use API for this named @Anywhere.

The first step in using @Anywhere is to register an application. In doing this you’ll identify the ultimate deployment URL of your application and receive both a consumer key and a consumer secret which will be used to positively identify your application as legitimate.



In the web application, we load the Twitter @Anywhere JavaScript library with a script line like this in the section of the web site.

<script src="http://platform.twitter.com/anywhere.js?id=yxWqT5gTZ4pfhw&v=1" type="text/javascript">script>

The result of this is that we’ll have a JavaScript object named twttr that we can reference for various behaviors.

Connect Button

To add a Connect to Twitter button to the site, we turn a placeholder div into a live sign-in interface using this invocation on the twttr object:

<script>
    twttr.anywhere(function (T) {
        T("#login").connectButton({ size: "medium" });
    });
script>


Tweet Box

To put up a tweet box, we invoke it this way. This pre-loads the tweet box with the hashtag “#outsideboxpizza”.

twttr.anywhere(function (T) {
    var width = document.getElementById('logo').offsetWidth - 20;

    T("#tbox").tweetBox(
    {
        height: 60,
        width: width,
        defaultContent: "#outsideboxpizza "
    });
});


Twitter Feed

Although we can also use the twttr object to get the Twitter feed for our hashtag, we chose here to use jTweetsAnywhere jQuery library which encapsulates the logic and nicely formats the display for us. After loading its JavaScript and CSS scripts, this code gives us our feed:

    $('#tweetFeed').jTweetsAnywhere({
        searchParams: 'q=outsideboxpizza',
        count: 5,
        showTweetFeed: {
            showProfileImages: true,
            showUserScreenNames: true,
            showUserFullNames: true,
            showActionReply: true,
            showActionRetweet: true,
            showActionFavorite: true,
            autorefresh: {
                mode: 'auto-insert',
                interval: 30
            }
        },
        showTweetBox: false
    });



Summary

Social integration is a key concern for modern web software. Outside-the-Box Pizza focuses on Twitter integration in the front end, using the Twitter @Anywhere API. The result is an ongoing social touchpoint with customers. Through the use of gamification, what might be viewed as a commodity, pizza, has been made into a fun, creative experience that consumers want to brag about over Twitter.

Next: Part 5: Hosting The Front End in the Cloud

Saturday, April 14, 2012

Outside-the-Box Pizza, Part 3: Mobility & Responsive Web Design

In this series, we’re looking at Outside-the-Box Pizza, a web-mobile-social-cloud demo, from a variety of perspectives that include design, technologies, and techniques. The online demo is at http://outsidetheboxpizza.com. Here in Part 3, we’ll be looking at how the app supports mobile devices, primarily through the technique of Responsive Web Design. We’ve seen the desktop browser experience, but how does Outside the Box Pizza render on smartphones and tablets? We’ll look at four things:
·         Responsive Web Design and CSS3 Media Queries
·         Font Size and Responsive Text
·         Running Full-Screen on the iPad
·         Sticky Footers

The Goal: Broad Reach
We want our web applications to have broad reach, to work on as many devices as possible. Below you can see some examples of Outside the Box Pizza on various devices. It renders acceptably on smartphones (iPhone, Android, Windows Phone 7), tablets (iPad, Windows 8), and desktop browsers (Chrome, Firefox, Safari, Internet Explorer). It also handles orientation changes on smartphones and tablets.
Outside-the-Box Pizza on various Phones and Tablets

Responsive Web Design & CSS3 Media Queries
The key technique to support a wide variety of modern devices well is Responsive Web Design, the brainchild of Ethan Marcotte. His book on the subject is highly recommended. Responsive Web Design is about adapting to the device we find ourself running on and not making assumption in advance. The most articulated aspect of RWD is adaptive layout for different size and orientation devices, but the principal can be extended to other areas. Let’s first look at device dimensions.
We can use the CSS3 media queries feature to have conditional CSS styling that only applies to devices meeting certain criteria. For example, this is how we express conditional styling in our CSS that should apply to smartphones, which generally have a width of 320 to 480 pixels:
/********************
*                   *
*   Mobile Styles   *
*                   *
********************/

@media only screen and (max-width: 480px) {
    header .float-left, header .float-right {
        float: none;
    }

    header .site-title {
        margin: 10px;
        text-align: center;
    }
    
    .selectGroup li 
    {
        display: inline-block; width: 120px 
    }
    
    h1 { font-size: 1.4em; }
    h2 { display: none; }
    
    .logo { font-size: 1.75em }
    .logo i { display: none }
    .text i { display: none }
    .text b { display: none }

    span b { display: none }
    span i { display: none }
    button b { display: none }
    article { font-size: 0.8em }
    article i { display: none }
    article B { display: none }

    ...


In our case the default CSS is for the desktop browser and our conditional CSS adapts to smaller mobile device dimensions, but I should point out that an alternative way to go is to have your default styles target phones and use conditional styling for larger sizes. Today we have pretty widespread support for HTML5 and CSS3 media queries in our mobile browsers, but when that was less common doing what I just described was important so that the default rendering of the site on “dumb phones” would still be acceptable. Supporting dumb phones wasn’t a priority in this application.
None of the styles in these conditional sections are new; that is, all of the style rules have been previously defined in the base CSS. Rather, what we’re doing here is overriding many of our styles for the small device. There are several reasons to override styles for smaller size screens:
1.       Spacing. We may need to change margins and padding to reduce white space.
2.       Sizes. We may need to change widths, or heights.
3.       Type. We may need to change font characteristics such as size or font family.
4.       Hiding. We may need to hide elements for which we don’t have room to show.
5.       Layout. We may choose to arrange elements differently.
You can reduce the amount of work you need to do here by thinking in percentages as RW advocates. The more we use percentages in our CSS styling rather than fixed units, the less need there is for conditional styles.

Layout Flow
We can solve a lot of problems simply by choosing our layout flow wisely. For example, Outside-the-Box Pizza has an orders page in which many choices are listed for pizza shape, sauce, meat toppings, and veggie toppings. These are all expressed as list items, which are styled such that the browser will intelligently wrap as many across as possible. Notice how this renders on various screen sizes:
Orders Page on Various Mobile Devices
Also notice the toppings icons are designed to be easily touched as well as clicked. When a topping is active, we mark the item as checked and use styling to show its bounding circle in green rather than gray (the “circles” are actually rectangular borders with a generous border radius).
Order Topping Items Designed to be Touch-friendly
Here’s the style for the order list items and how the list items are defined:

.topping { font-family: Arial, Helvetica; font-size: 1.0em; color: Black }
.topping input { display: none; vertical-align: middle; margin-right: 4px; }
.topping span { font-family: Arial, Helvetica; font-size: 1.2em; color: Black }
.topping label { display: inline; font-family: Arial, Helvetica; font-size: 1.2em; color: Black; vertical-align: middle; }

.topping:checked { background-color: #C00000 }
.topping:checked+label { background-color: #C00000 }

.topping img { display: inline; vertical-align: middle; margin-right: 4px; height: 48px;
               border: 4px solid Silver;
               -webkit-border-radius: 32px;
               -moz-border-radius: 32px;
               border-radius: 32px;   
}


<div class="selectGroup">
<div class="selectGroupTitle">Meat Toppings</div>
<ul>
<li class="topping"><label for="topPepperoni"><img src="~/Images/topping_pepperoni.png"  alt="image"/><input id="topPepperoni" name="jqdemo" value="value1" type="checkbox"/>pepperoni</label></li>
<li class="topping"><label for="topSausage"><img src="~/Images/topping_sausage.png"  alt="image"/><input id="topSausage" name="jqdemo" value="value1" type="checkbox"/>sausage</label></li>
<li class="topping"><label for="topHam"><img src="~/Images/topping_ham.png"  alt="image"/><input id="topHam" name="jqdemo" value="value1" type="checkbox"/>ham</label></li>
<li class="topping"><label for="topBacon"><img src="~/Images/topping_bacon.png"  alt="image"/><input id="topBacon" name="jqdemo" value="value1" type="checkbox"/>bacon</label></li>
<li class="topping"><label for="topBeef"><img src="~/Images/topping_beef.png"  alt="image"/><input id="topBeef" name="jqdemo" value="value1" type="checkbox"/>beef</label></li>
<li class="topping"><label for="topChicken"><img src="~/Images/topping_chicken.png"  alt="image"/><input id="topChicken" name="jqdemo" value="value1" type="checkbox"/>chicken</label></li>
<li class="topping"><label for="topTurkey"><img src="~/Images/topping_turkey.png"  alt="image"/><input id="topTurkey" name="jqdemo" value="value1" type="checkbox"/>turkey</label></li>
<li class="topping"><label for="topElk"><img src="~/Images/topping_elk.png"  alt="image"/><input id="topElk" name="jqdemo" value="value1" type="checkbox"/>elk</label></li>
<li class="topping"><label for="topSardines"><img src="~/Images/topping_sardine.png"  alt="image"/><input id="topSardines" name="jqdemo" value="value1" type="checkbox"/>sardines</label></li>
<li class="topping"><label for="topEgg"><img src="~/Images/topping_egg.png"  alt="image"/><input id="topEgg" name="jqdemo" value="value1" type="checkbox"/>egg</label></li>
</ul>
</div>

<div class="selectGroup">
<div class="selectGroupTitle">Veggie Toppings</div>
<ul>
<li class="topping selectedTopping"><label for="topCheese"><img src="~/Images/topping_cheese.png"  alt="image"/><input id="topCheese" name="jqdemo" value="value1" type="checkbox" checked="checked"/>cheese</label></li>
<li class="topping"><label for="topTomato"><img src="~/Images/topping_tomato.png"  alt="image"/><input id="topTomato" name="jqdemo" value="value1" type="checkbox"/>tomatoes</label></li>
<li class="topping"><label for="topPineapple"><img src="~/Images/topping_pineapple.png"  alt="image"/><input id="topPineapple" name="jqdemo" value="value1" type="checkbox"/>pineapple</label></li>
<li class="topping"><label for="topOnions"><img src="~/Images/topping_onion.png"  alt="image"/><input id="topOnions" name="jqdemo" value="value1" type="checkbox"/>onions</label></li>
<li class="topping"><label for="topPeppers"><img src="~/Images/topping_pepper.png"  alt="image"/><input id="topPeppers" name="jqdemo" value="value1" type="checkbox"/>peppers</label></li>
<li class="topping"><label for="topSprouts"><img src="~/Images/topping_sprouts.png"  alt="image"/><input id="topSprouts" name="jqdemo" value="value1" type="checkbox"/>sprouts</label></li>
<li class="topping"><label for="topArtichoke"><img src="~/Images/topping_artichoke.png"  alt="image"/><input id="topArtichoke" name="jqdemo" value="value1" type="checkbox"/>artichoke</label></li>
<li class="topping"><label for="topGorgonzola"><img src="~/Images/topping_gorgonzola.png" alt="image" /><input id="topGorgonzola" name="jqdemo" value="value1" type="checkbox"/>gorgonzo</label></li>
<li class="topping"><label for="topBroccoli"><img src="~/Images/topping_broccoli.png" alt="image" /><input id="topBroccoli" name="jqdemo" value="value1" type="checkbox"/>broccoli</label></li>
<li class="topping"><label for="topPotato"><img src="~/Images/topping_potato.png" alt="image" /><input id="topPotato" name="jqdemo" value="value1" type="checkbox"/>m. potato</label></li>
</ul>
</div>

 
Font Size and Responsive Text
The main thing RWD has to say about text is to set font sizes based on “em” units rather than fixed unit sizes like pixels. In typography, an “em” is the width of the capital letter M in a typeface. Since we want to preserve a user’s right to control the default font size in their browser (for accessibility reasons, for example), doing all of our type setting relative to the “em” is the best approach. Thus our type settings for headings, text, button captions, etc. are all based on the em. Again, we may choose to use different proportions in our conditional styles for some devices.
h1 {
    font-size: 1.8em;
}

h2 {
    font-size: 1.5em;
}

h3 {
    font-size: 1.2em;
}

Another thing we can do to apply the philosophy of RWD to text is to responsive text, which has to do with right-sizing the amount of text content we display. For example, the navigation buttons and top-of-page text on a desktop browser look like this:
Desktop Button Captions and Page Text
…whereas on a phone they look like this, with shorter button captions and shorter page text. The button caption shortening prevents the buttons from wrapping to the next line on many phones. The text shortening prevents the text from taking up too much of the screen so that the content below can be seen without scrolling.

Phone Button Captions and Page Text
Implementing responsive text is a simple matter of choosing some text emphasis style (like <b> or <i>) and defining it to be visible for large screens and hidden on small screens. This is how the button captions and page text are defined in the HTML:
        <nav>
            <div class="content-wrapper">
                <button id="buttonSpecialOffers" class="buttonUnselected" #nclick="javasc#ipt:window.location.href = '/';"><b>Special&nbsp;</b>Offers</button>
                <button id="buttonOrderPizza" class="buttonUnselected" #nclick="javasc#ipt:window.location.href = '/Order';">Order<b>&nbsp;Pizza</b></button>
                <button id="buttonTweet" class="buttonUnselected" #nclick="javasc#ipt:window.location.href = '/Share';">Tweet<b>za&nbsp;Pizza</b></button>
                <button id="buttonPizzaSightings" class="buttonUnselected" #nclick="javasc#ipt:window.location.href = '/Cool';">Cool<b>&nbsp;Pizzas</b></button>
            </div>
        </nav>


All it takes to apply this simply technique with finesse is to think through where you use longer and shorter text and ensure both versions communicate your intent well. Here’s another example of responsive page text:

<span class="text">Ordered an unusual pizza for an unusual occasion? Tweet it and you may win a discount<i> on your next order. We regularly award prizes for most unusual pizza, most unusual occasion, and even most unusual customer<i>!<span>


Full Screen on the iPad
When you access a web application on the iPad, this is how the app will look in the Safari Mobile browser by default. While there’s nothing wrong with the web display, we’d really like the app to have more the look of a native app, preferably running full screen without the browser’s tabs or address bar being visible.
Outside the Box Pizza on iPad - Default Appearance
We can achieve this on the iPad by 1) adding the HTML meta element below to our markup and 2) getting the user to add the web site to their home screen.

<meta name="apple-mobile-web-app-capable" content="yes" />
With the above accomplished, the “app” now has an app icon on the home screen and when invoked runs full-screen. The entire experience is now much closer to that of a native app.
Outside the Box Pizza on iPad - Full Screen
Responsive Images
One other area you should be looking at is sizing your images appropriate for your target device. You don’t want to send a large, hi-resolution image to a phone that is incapable of showing it that way: it’s a waste of bandwidth and slows down you app’s loading and rendering time.
We haven’t put responsive images into place yet in Outside the Box Pizza, but we will be doing so (and will update this post when that happens).

Sticky Footers
A sticky footer will smartly snap to the bottom of the display, which looks a lot more app-like than simply appearing at the end of the content. Sticky footers are best done in CSS (rather than JavaScript): they flow more smoothly and are less-taxing. A well-done sticky footer will also detect and handle long scrolling pages and in that case simply put the footer at the end of the content. Here’s a technique for a sticky footer in CSS you can use (source: http://ryanfait.com/sticky-footer/).
Here’s the relevant CSS for Outside-the-Box Pizza: 
html {
    margin: 0;
    padding: 0;
}

html, body 
{
    height: 100%;
}

#wrap 
{
    min-height: 100%;
    height: auto !important;
    height: 100%;
    margin: 0 auto -3.0em; /* Set footer height. */
}
footer, .push {
    height: 3.0em; /* Set footer height. */
}


Here’s what the rules do:
·         The first rule performs a reset of margin and padding for everything in the document.
·         The second rule sets the height to 100% for the html and body elements.
·         The #wrap rule defines a wrapper style, which will enclose everything in the body except the footer.
·         The .footer / .push rule makes space for the footer.
Notice the height in the #wrap rule is -1 x the height specified in the footer / .push rule. You can use any height you wish, but they must match.
In the HTML markup, we enclose the entire contents of your body in a wrapper div, except the footer – wrap that in a div with the footer class. The wrapper div should include a div with class push at the bottom which is empty. That’s all there is to it.
<div id="wrap">
        <header>
            <div id="banner" class="content-wrapper">
                <div id="logo" class="logo">
                    <div>outside&nbsp;the&nbsp;box&nbsp;<b>pizza</b>&nbsp;<img src="http://outsidetheboxpizza.blob.core.windows.net/images/icon.png" alt="icon" /></div>
<div><i>pizza&nbsp;as&nbsp;individual&nbsp;as&nbsp;you&nbsp;are.</i></div>
                </div>
            </div>
        </header>

        <nav>
            <div class="content-wrapper">
                <button id="buttonSpecialOffers" class="buttonUnselected" onclick="javascript:window.location.href = '/';"><b>Special&nbsp;</b>Offers</button>
                <button id="buttonOrderPizza" class="buttonUnselected" onclick="javascript:window.location.href = '/Order';">Order<b>&nbsp;Pizza</b></button>
                <button id="buttonTweet" class="buttonUnselected" onclick="javascript:window.location.href = '/Share';">Tweet<b>za&nbsp;Pizza</b></button>
                <button id="buttonPizzaSightings" class="buttonUnselected" onclick="javascript:window.location.href = '/Cool';">Cool<b>&nbsp;Pizzas</b></button>
            </div>
        </nav>

        <div id="body">
            <section class="content-wrapper main-content clear-fix">
                @RenderBody()
            </section>
        </div>

        <div class="push"><!--Sticky Footer Push--></div>
    </div>

    <footer>
        <div class="content-wrapper" style="line-height: 3.0em">
            <div class="logo">
            <span style="float: left; color: White; font-size: 0.65em; margin-right: 8px;"><a style="color: White; font-size: 0.75em" href="/Activity" >Sales</a></span>
            <span style="float: left; color: White; font-size: 0.65em; margin-right: 8px;"><a id="StoreLink" style="color: White; font-size: 0.75em" href="/Store/Orders/@ViewBag.StoreId">Store</a></span>
            <span style="float: left; color: White; font-size: 0.65em; margin-right: 8px;"><a id="DeliveryLink" style="color: White; font-size: 0.75em" href="/Store/Driver/@ViewBag.StoreId">Driver</a></span>
            <span style="float: right; color: White; font-size: 0.65em; margin-right: 10px"><a style="color: White; text-decoration: none; font-size: 0.75em" href="/Home/About">About</a></span>
        </div>
        </div>
    </footer>


Summary
Outside-the-Box Pizza leverages responsive web design to adapt its layout to many kinds and sizes of device in order to extend its reach. It renders well on desktop browsers, tablets, and smartphones. Beyond layout, the principle of responsive web design is also seen in the use of responsive text and, in the future, responsive images. Using sticky footers makes the web application seem more like a native app, as does going full-screen if the platform/browser provides a means of achieving that.


Next: Part 4: Social Integration with Twitter

Tuesday, April 10, 2012

CSS3 Animation and Transitions Tutorial: Soccer Ball Animation

In this post we’ll show you how we created a soccer ball animation using CSS3 animation and transitions. We’ll do this in 6 steps. You can see each step as well as the final result here (you’ll need a screen width of 1650 pixels or more).

The soccer ball shoots up into the air from the left side of the field and goes back down to the right side of the field. This goes back and forth for a total of 3 animations. There is also a transition you can trigger once the animation completes: hovering over the ball hurls it up into the face of a spectator in the foreground at bottom right.


Here are the steps:

1. Setting up a Foundation with Modernizr
2. Animating Size
3. Animating Position
4. Animation Rotation
5. Supporting Multiple Browsers
6. Adding a Transition


Step 1: Setting up a Foundation with Modernizr

In Step 1 we start with a basic page that has a div with an image for the soccer field (‘field’) and another with an image for the ball (‘ball’).

DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"  class="no-js">
<head>
...
<head>
<body>

<div id="notsupported">Sorry, Your Browser DOES NOT Support CSS Animations and Transitionsdiv>
<div id="supported">Yay, Your Browser DOES Support CSS Animations and Transitionsdiv>

<div class="field">
    <img src="background.jpg" alt="field" />
div>

<div class="ball">
    <img src="ball.png" alt="ball" />
div>

<body>
<html>

We want to use the Modernizr library to test for the availability of the features we need, which in this case is css animations and transitions.  We include it in the area of our page.

<script src="http://ajax.aspnetcdn.com/ajax/modernizr/modernizr-2.0.6-development-only.js" type="text/javascript"<script>

If css animations and transitions are not present, we want to display the following red sorry message and hide the field and ball.


If we do have animations and transitions available, we display a green confirming message, show the field and ball:


We accomplish this with the following CSS styles. This works because Modernizr will set classes on the element with names like cssanimations, no-cssanimations, etc. based on the features it detects.

  <style type="text/css">

    /* Display whether or not CSS Animations and Transitions are supported */
     
    .cssanimations #notsupported {
        display: none;
    }

    .cssanimations #supported {
        display: inline;
        padding: 8px;
        background-color: green;
        color: white;
        font-family: Sans-Serif;
    }
       
    .no-cssanimations #notsupported {
        display: inline;
        padding: 8px;
        background-color: red;
        color: white;
        font-family: Sans-Serif;
    }

    .no-cssanimations #supported {
        display: none;
    }

    .no-cssanimations .field {
        display: none;
    }

    .no-cssanimations .ball {
        display: none;
    }


    .csstransitions #notsupported {
        display: none;
    }

    .csstransitions #supported {
        display: inline;
        padding: 8px;
        background-color: Green;
        color: White;
    }
       
    .no-csstransitions #notsupported {
        display: inline;
        padding: 8px;
        background-color: Red;
        color: White;
    }

    .no-csstransitions #supported {
        display: none;
    }

    .no-csstransitions .field {
        display: none;
    }

    .no-csstransitions .ball {
        display: none;
    }


    /* Image of soccer stadium, field, and crowd */

    .field {
        position: absolute;
        top: 150px;
        left: 0px;
        height: 300px;
        width: 1500px;
        text-align: left;
    }


    /* Ball container */

    .ball
    {
        position: absolute;
        top: 300px;
        left: 700px;
        height: 200px;
        width: 200px;
    }


    /* Ball image */

    .ball img
    {
        max-height: 100%;
        max-width: 100%;
    }

  <style>

When we run this in common browsers, we get the red not supported message in IE9 and the green confirming message in IE10, Chrome, Firefox, and Safari.


Step 2: Animating Size

Now we want to put some animation in place, starting with the size of the ball. To do CSS animation today, you need to use vendor prefixes since theimplementations are pre-ratification of the standards. That means instead of using style properties like animate: we’ll be using –webkit-animate for web kit (Chrome, Safari), -moz-animate for Firefox, and –ms-animate for IE. For now, we’ll just put in the –webkit prefix and add the others in a later step.

In the CSS, we achieve the animation by defining a keyframes animation (‘throwing’) and then referring the animation in the style rule for ball. Let’s parse the animation reference in the .ball rule first. The line below means, for webkit browsers, apply the animation ‘throwing’ over a duration of 10 seconds, do it three times, and alternate direction every other time.

-webkit-animation: throwing 10s 3 alternate;

The keyframes animation indicates changes at 0%, 50%, and 100% of the animation. Size goes from 5px height and width to 200px at the midpoint and back down to 5px at end. This gives the effect of a ball getting closer and closer at it soars toward us, then falls back again down to the field.

    /* Animation keyframes */

    @-webkit-keyframes throwing {
        0% { height: 5px; width: 5px; }
        50% { height: 200px; width: 200px; }
        100% { height: 5px; width: 5px; }
    }

Animating size is a good first step, but we’ll need to animate some other characteristics in order to make this effect more convincing.



Step 3: Animating Position

Now that we have the ball size animating, let’s control the start, middle, and end position of the ball to correspond with areas of the background soccer field image. To do this, we simply expand the keyframes animation to also modify the top and left positions.
    /* Animation keyframes */

    @-webkit-keyframes throwing {
        0% { height: 5px; width: 5px; top: 580px; left: 660px }
        50% { height: 200px; width: 200px; top: 50px; left: 800px }
        100% { height: 5px; width: 5pxtop: 400px; left: 875px }
    }

Now our ball grows in size and has a movement path that aligns with the background. It even pops out of its bounding frame, seemingly.


Step 4: Animating Rotation

A final touch on the animation is to have the ball rotate. We can achieve that by also adding a transform that rotates the ball. We’ll rotate to 180 degrees by midpoint and on to 360 by the end.

    /* Animation keyframes */

    @-webkit-keyframes throwing {
        0% { height: 5px; width: 5px; top: 580px; left: 660px }
        50% { -webkit-transform: rotate(180deg); height: 200px; width: 200px; top: 50px; left: 800px }
        100% { -webkit-transform: rotate(360deg); height: 5px; width: 5pxtop: 400px; left: 875px }
    }



Step 5: Supporting Multiple Browsers

Up till now we’ve just been putting the –webkit-xxx animation keywords, which gets us working in Chrome and Safari. Now we want to support Firefox and IE as well. We’ll do that by adding –moz-xxx and –ms-xxx keywords. Here’s our updated style.

  <style type="text/css">

    ...

    /* Ball container */

    .ball
    {
        position: absolute;
        top: 400px;
        left: 875px;
        height: 5px;
        width: 5px;
   
        -webkit-animation: throwing 10s 3 alternate;
        -moz-animation: throwing 10s 3 alternate;
        -ms-animation: throwing 10s 3 alternate;
        animation: throwing 10s 3 alternate;
    }


    /* Ball image */

    .ball img
    {
        max-height: 100%;
        max-width: 100%;
    }


    /* Animation keyframes */

    @-webkit-keyframes throwing {
        0% { height: 5px; width: 5px; top: 580px; left: 660px }
        50% { -webkit-transform: rotate(180deg); height: 200px; width: 200px; top: 50px; left: 800px }
        100% { -webkit-transform: rotate(360deg); height: 5px; width: 5pxtop: 400px; left: 875px }
    }

    @-moz-keyframes throwing {
        0% { height: 5px; width: 5px; top: 580px; left: 660px }
        50% { -moz-transform: rotate(180deg); height: 200px; width: 200px; top: 50px; left: 800px }
        100% { -moz-transform: rotate(360deg); height: 5px; width: 5pxtop: 400px; left: 875px }
    }

    @-ms-keyframes throwing {
        0% { height: 5px; width: 5px; top: 580px; left: 660px }
        50% { -ms-transform: rotate(180deg); height: 200px; width: 200px; top: 50px; left: 800px }
        100% { -ms-transform: rotate(360deg); height: 5px; width: 5pxtop: 400px; left: 875px }
    }

    @keyframes throwing {
        0% { height: 5px; width: 5px; top: 580px; left: 660px }
        50% { transform: rotate(180deg); height: 200px; width: 200px; top: 50px; left: 800px }
        100% { transform: rotate(360deg); height: 5px; width: 5pxtop: 400px; left: 875px }
    }

  <style>

Now we can perform the animation with IE10 and the latest versions of Chrome, Firefox, and Safari. If we wanted to also support Opera or additional browsers that support animation, it’s just a matter of also including their prefixes as well.


Step 6: Adding a Transition

We’ve done animations up till now, which are applied immediately upon definition. Transitions, in contrast, are trigged by some action. We’ll add a transition that hurls the ball into a spectator, and we’ll trigger it when the ball is hovered over.


We define a hover style rule for ball that changes position, size, and rotation:

    /* Hover transition */
   
    .ball:hover
    {
        height: 200px;
        width: 200px
        top: 480px;
        left: 1100px;
   
        -webkit-transform: rotate(360deg);
        /* -moz-transform: rotate(360deg);  <= breaks hover transition in Firefox, presumably a bug */
        -ms-transform: rotate(360deg);
        transform: rotate(360deg);
    }

We then reference the transition in the rule for ball, specifying a 10 second duration.

    /* Ball container */

    .ball
    {
        position: absolute;
        top: 400px;
        left: 875px;
        height: 5px;
        width: 5px;
   
        -webkit-animation: throwing 10s 3 alternate;
        -moz-animation: throwing 10s 3 alternate;
        -ms-animation: throwing 10s 3 alternate;
        animation: throwing 10s 3 alternate;
   
        -webkit-transition: all 10s;
        -moz-transition: all 10s;
        -ms-transition: all 10s;
        transition: all 10s;
    }

Here’s the updated style:

  <style type="text/css">

    ...

    /* Image of soccer stadium, field, and crowd */

    .field {
        position: absolute;
        top: 150px;
        left: 0px;
        height: 300px;
        width: 1500px;
        text-align: left;
    }


    /* Ball container */

    .ball
    {
        position: absolute;
        top: 400px;
        left: 875px;
        height: 5px;
        width: 5px;
   
        -webkit-animation: throwing 10s 3 alternate;
        -moz-animation: throwing 10s 3 alternate;
        -ms-animation: throwing 10s 3 alternate;
        animation: throwing 10s 3 alternate;
   
        -webkit-transition: all 10s;
        -moz-transition: all 10s;
        -ms-transition: all 10s;
        transition: all 10s;
    }


    /* Ball image */

    .ball img
    {
        max-height: 100%;
        max-width: 100%;
    }


    /* Animation keyframes */

    @-webkit-keyframes throwing {
        0% { height: 5px; width: 5px; top: 580px; left: 660px }
        50% { -webkit-transform: rotate(180deg); height: 200px; width: 200px; top: 50px; left: 800px }
        100% { -webkit-transform: rotate(360deg); height: 5px; width: 5pxtop: 400px; left: 875px }
    }

    @-moz-keyframes throwing {
        0% { height: 5px; width: 5px; top: 580px; left: 660px }
        50% { -moz-transform: rotate(180deg); height: 200px; width: 200px; top: 50px; left: 800px }
        100% { -moz-transform: rotate(360deg); height: 5px; width: 5pxtop: 400px; left: 875px }
    }

    @-ms-keyframes throwing {
        0% { height: 5px; width: 5px; top: 580px; left: 660px }
        50% { -ms-transform: rotate(180deg); height: 200px; width: 200px; top: 50px; left: 800px }
        100% { -ms-transform: rotate(360deg); height: 5px; width: 5pxtop: 400px; left: 875px }
    }

    @keyframes throwing {
        0% { height: 5px; width: 5px; top: 580px; left: 660px }
        50% { transform: rotate(180deg); height: 200px; width: 200px; top: 50px; left: 800px }
        100% { transform: rotate(360deg); height: 5px; width: 5pxtop: 400px; left: 875px }
    }


    /* Hover transition */
   
    .ball:hover
    {
        height: 200px;
        width: 200px
        top: 480px;
        left: 1100px;
   
        -webkit-transform: rotate(360deg);
        /* -moz-transform: rotate(360deg);  <= breaks hover transition in Firefox, presumably a bug */
        -ms-transform: rotate(360deg);
        transform: rotate(360deg);
    }

  <style>


Summary

CSS animations and transitions are extremely powerful and fairly easy to learn, but their lack of ubiquity requires discipline in checking for feature availability for which Modernizr is invaluable. A good animation or transition needs to be planned out and storyboarded, much like a movie scene, before it is clear what needs to be done to cleanly implement it.

To see the source, visit the online demo, pull up any of the steps, and view source (each is a single page).