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:
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).
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.
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 </b>Offers</button> <button id="buttonOrderPizza" class="buttonUnselected" #nclick="javasc#ipt:window.location.href = '/Order';">Order<b> Pizza</b></button> <button id="buttonTweet" class="buttonUnselected" #nclick="javasc#ipt:window.location.href = '/Share';">Tweet<b>za Pizza</b></button> <button id="buttonPizzaSightings" class="buttonUnselected" #nclick="javasc#ipt:window.location.href = '/Cool';">Cool<b> 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 the box <b>pizza</b> <img src="http://outsidetheboxpizza.blob.core.windows.net/images/icon.png" alt="icon" /></div> <div><i>pizza as individual as you are.</i></div> </div> </div> </header> <nav> <div class="content-wrapper"> <button id="buttonSpecialOffers" class="buttonUnselected" onclick="javascript:window.location.href = '/';"><b>Special </b>Offers</button> <button id="buttonOrderPizza" class="buttonUnselected" onclick="javascript:window.location.href = '/Order';">Order<b> Pizza</b></button> <button id="buttonTweet" class="buttonUnselected" onclick="javascript:window.location.href = '/Share';">Tweet<b>za Pizza</b></button> <button id="buttonPizzaSightings" class="buttonUnselected" onclick="javascript:window.location.href = '/Cool';">Cool<b> 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
Next: Part 4: Social Integration with Twitter
No comments:
Post a Comment