Up till now we’ve been writing and re-writing the desktop version of the Save Sick Child application. Will it look good on the small screen of a mobile device?
Let’s discuss different approaches to making the Web site for mobile devices. One of the approaches is having only one Web site for all devices. There are three choices:
-
Develop separate version of native applications for each mobile device. Developing of native mobile applications is not covered in this book.
-
Develop one HTML5 Web application, but create several different UI layouts that will be applied automatically based on the screen size of the user’s device.
-
Develop a hybrid application, which is a Web application on steroids - it can invoke native API of the mobile device. Chapter 14 is dedicated to hybrid applications.
The chapter is about the second approach called Responsive Design. This term was coined by Ethan Marcotte is the article Responsive Web Design. The design of the Web page changes responding (reacting) to the user’s display size. We’ll modify the design of the Save Sick Child site to introduce different layouts for the desktop, tablet, and smart phones. By the end of this chapter the site Save Sick Child will automatically change its layout based on the user’s device without the losing functionality.
Run any of the versions of our Save Sick Child applications on your desktop and start dragging the right border of the browser’s window to make it narrower. At some point you’ll see only a part of the content - the layout of Save Sick Child was not meant to be responsive. It defined fixed sizes for the page sections, which didn’t change even if the display area shrinks.
Enter the address of one of the Save Sick Child projects in your mobile phone’s browser. Either you’ll see a partial content of the page or the entire page with illegible small fonts. Our design of the Save Sick Child application doesn’t look good on all devices.
How many versions of the UI do we need to create then? People responsible for developing a Web applications that can run on both desktop and mobile platforms usually start with making an important decision: HTML5 or native? But even if a decision was made in the favor of the Web platform, the next question is if the desktop and mobile clients will use the same code or not.
If a decision is made to go with separate versions of the Web applications, the Web server can be configured to perform the redirection to the appropriate code depending on the type of the user’s device. Web servers can do it based on the value of the User-Agent
attribute of the HTTP request header. For example, the mobile Web browsers trying to access of BBC (or any other Web page) report their User-Agent
to the server differently from desktop computers hence they receive different content delivered from a different URL. The snapshots The desktop version of bbc.com and The mobile version of bbc.com of the BBC main page were taken at the same time, but The desktop version of bbc.com shows how the page looks on the desktop computer, while The mobile version of bbc.com was taken from the iPhone.
The The desktop version of bbc.com page layout delivers more content as it can be allocated nicely on the large desktop monitor or a tablet. But the mobile version on The mobile version of bbc.com substantially limits what’s delivered to the client, which is done not only because the screen is small, but the user may be accessing the page over the slower network.
Have you ever tried to share the link of the Web site from your iPhone? It’s so easy! Just press the button and enter the email of the person to share the site with. Go to bbc.com from your iPhone or Android phone and share this link with someone. That person will receive the link http://www.bbc.co.uk/mobile/i, and if she’s visit this site from the desktop it won’t look pretty. It’ll just show the wider version of what you see in The mobile version of bbc.com. Try to enter this URL in your desktop browser to see for yourself.
Maintaining two different versions of the application code requires more efforts than maintaining one: you need to have two sets of HTML, CSS, JavaScript, and images. Besides, most likely your Web application will use a third-party JavaScript framework. At some point you may run into a bug and will need to upgrade the mobile version to use the latest version of, say jQuery framework. But the desktop version works just fine. In case of having two separate versions of the application you’ll have to either upgrade jQuery and thoroughly test both mobile and desktop versions of Save Sick Child, or live with two different versions of the framework.
Responsive design allows you to create one version of the Web application, which includes multiple sections of CSS controlling page layouts for different screen sizes. In this chapter we’ll create yet another version of the Save Sick Child application that will render UI differently on desktop and mobile devices. All these version will share the same HTML and JavaScript code, but will include several versions of styling using CSS media queries.
There is a number of Web sites that were built using responsive design. Visit the following Web sites first from the desktop computer and then from smart phones (or just lower the width of the desktop browser window) to experience such fluid responsive design:
Note that each of these Web pages displays the content on the desktop in three different layouts (often in three imaginary columns). As you make the window narrower, the layout will automatically switch to the tablet or a large smartphone mode (usually two columns layout), and then to the phone mode layout (the one column layout).
This sounds like a great solution, but keep in mind that your users will be downloading unnecessary bytes - the entire CSS file that includes all versions of screen layouts. This is not the case in the BBC example, which has different versions of the code that load only what’s necessary for a particular device category.
Now comes the million dollar question, "Do we need to create two different versions of the Web application or twenty two? Why not two hundred and twenty two?" How many different mobile devices are there today and will be there tomorrow?
The HTTP header’s attribute User-Agent
contains information about the user agent originating request. Should you decide to create several versions of the UI based on the value in the User-Agent
field, you can refer to the Web site http://useragentstring.com. It lists not two, but hundreds of strings representing possible content of the User-Agent
attribute for a variety of desktop and mobile devices. For example, The User-Agent String from iPhone 5 shows how the User-Agent
string from iPhone5 is reported and explained by useragentstring.com.
It’s impossible to create different layouts of a Web application for thousands of user agents. Grouping devices by screen sizes is a more practical approach for lowering the number of UI layouts supported by your application. The responsive design is a collection of techniques based upon three pillars:
-
CSS media queries
-
Fluid grids or fluid layouts
-
Fluid media
Media queries allows to rearrange the sections (`<div>’s') of the page based on the screen size, fluid grids allows to properly scale the content of these sections, and the fluid media is about resizing images or videos. But before going into technical details, let’s get back to the mockups to see how the UI should look like on different devices.
Jerry, our Web designer came up with another set of Balsamiq mockups for the Save Sick Child application. This time he had four different versions: desktop, tablet, large phone, and small phone. As a matter of fact, Jerry provided more mockups - the user can hold both smartphones and tablets either in portrait or landscape mode. The Desktop layout, The tablet layout (portrait), and The large phone layout (portrait), The small phone layout (portrait) show the screenshots taken from Balsamiq Mockups for desktop, tablet, large, and small phone layouts. The Desktop layout shows the desktop mockup.
Jerry gave us several version of the images - with and without the grid background. The use of the grid will be explained later in the section "Fluid Grids". The tablet layout (portrait) depicts the rendering on tablet devices that fall in a category of under 768px width screen in the portrait mode.
Next comes the mockup for the large smart phones having the width of up to 640 pixels. The large phone layout (portrait) shows two different images of the screen next to each other (the user would need to scroll to see the second image).
The mockup for the smaller phones with the width of under 480 pixels is shown on The small phone layout (portrait). The mockup looks wide, but it actually shows three views of the phone screen next to each other. The user would need to scroll vertically to see the middle or the right view. Physical screens are not too small - iPhone 3 falls into this category, but resolution-wise they are smaller.
If need be, you can ask Jerry to create mocupts for the really devices with the width under 320 pixels, but we won’t even try it here. Now we need to translate these mockups into working code. The first subject to learn is CSS media queries.
First, let’s see the CSS media queries in action, and then we’ll explain how this magic was done. Run Aptana’s project titled Responsive_basic_media_queries, and it’ll look as in The tesktop layout implemented. This is a desktop version for the desktops (or some tablets in the landscape mode). The section chart, map, and video divide the window into three imaginary columns.
Drag the right border of your desktop Web browser’s window to the left to make it narrower. After reaching certain breakpoint width (in our project it’s 768 pixels) you’ll see how the `<div>’s' reallocate themselves into the two-column window shown on The tablet layout (portrait) implemented.
Keep making the browser’s window narrower, and when the width will pass another breakpoint (becomes less than 640 pixels), the window will re-arrange itself into one long column as in The smaller phone layout (portrait) implemented. The users will have to use scrolling to see the lower portion of this window, but they don’t loose any content.
Media Queries is a W3C Recommendation that has been introduced in CSS2 and HTML4. The idea is to provide different stylesheets for different media. For example, you can specify different stylesheets in HTML using the media
for the regular screen and for the smaller ones (up to 640 pixel in width).
<link rel="stylesheet" href="assets/css/style.css" media="screen">
<link rel="stylesheet" href="assets/css/style_small.css" media="only screen and (max-width: 640px)">
The other choice is to specify a section in a CSS file using one or more @media
rules. For example, the following style will be applied to the HTML element with the id=main-top-section
if the width of the display area (screen) is less than 640 pixels. Screen is not the only media type that you can use with media queries. For example, you can use print
for printed documents. For the up to date list of media types see the W3C Media Queries Recommendation.
@media only screen and (max-width: 640px) {
#main-top-section {
width: 100%;
float: none;
}
}
The fragment of the CSS file styles.css from the project Responsive_basic_media_queries is shown next. It starts with defining styles for windows having 1280px width (we use 1140 pixels to leave some space for padding and browser’s chrome). This CSS mandates to change the page layouts if the screen size is or becomes below 768 or 640 pixels. Based on your Web designer’s recommendations you can specify as many breakout sizes as needed. Say, in the future, everyone will have at lease 1900px wide monitor - you can provide a layout that would use five imaginary columns. This can be a good idea for online newspapers or magazines, but Save Sick Child is not a publication so we keep its maximum width within 1140px. Or you may decide to make a version of Save Sick Child available for LCDs of only 320px in width - create a new media query section in your CSS and apply fluid grids to make the content readable.
/* The main container width should to be 90% of viewport width but not wider than 1140px */
#main-container {
width: 90%;
max-width: 1140px; // (1)
margin: 0 auto;
}
/* Background color of all elements was set just as an example */
header {
background: #ccc;
width: 100%;
height: 80px;
}
#main-top-section {
background: #bbb;
width: 100%;
height: 300px;
position: relative;
}
#main-bottom-section {
width: 100%;
}
#video-container, #map-container, #charts-container {
width: 33.333%; // (2)
padding-bottom: 33.333%;
float: left; // (3)
position: relative;
}
#video, #map, #charts {
background: #aaa;
width: 100%;
height: 100%;
position: absolute;
padding: 0.5em;
}
#map {
background: #999;
}
#charts {
background: #7d7d7d;
}
footer {
background: #555;
width: 100%;
height: 80px;
color: #fff;
}
/* media queries */
@media only screen and (max-width: 768px) { // (4)
#main-container {
width: 98%
}
#main {
background: #bbb;
}
#main-top-section, #main-bottom-section {
width: 50%; // (5)
float: left; // (6)
}
#main-top-section {
height: 100%;
}
#video-container, #map-container, #charts-container {
float: none; // (7)
width: 100%;
padding-bottom: 70%;
}
}
@media only screen and (max-width: 640px) { // (8)
#main-top-section, #main-bottom-section {
width: 100%; // (9)
float: none;
}
#main-top-section {
height: 400px;
}
#video, #map, #charts {
height: 60%;
}
}
-
Setting the maximum width of the window on a desktop to 1140 pixels. It’s safe to assume that any modern monitor supports the resolution of 1280px width (minus about 10% for padding and chrome).
-
Allocate one third of the width for video, charts, and maps each.
-
Float left instructs the browser to render each of these divs starting from the left and adding the next one to the right.
-
The media query controlling layouts for devices with viewports with the max width of 768px starts here.
-
Split the width fifty-fifty between the HTML elements with ID’s main-top-section and main-bottom-section.
-
Allocate main-top-section and main-bottom-section next to each other (
float: left;
) as in The tablet layout (portrait) implemented. To better understand how the CSSfloat
property works, visualize a book page having an small image on the left with the text floating on the right (a text wrap) - this is whatfloat: left;
can do on a Web page. -
Turn the floating off so the charts, maps, and video containers will start one under another as in The tablet layout (portrait) implemented.
-
The media query controlling layouts for devices with viewports with the max width of 640px starts here.
-
Let the containers main-top-section, main-bottom-section take the entire width and be displayed one under another (
float: none;
) as in The smaller phone layout (portrait) implemented.
Tip
|
Internet Explorer 8 and older don’t natively support media queries. Consider using Modernizr to detect support of this feature, and load the Media Queries Polyfill, if needed. |
Mobile browsers use a concept of viewport, which is a virtual window where they render the Web page content. This virtual window can be wider than the actual width of the display of the user’s mobile device. For example, by default iOS Safari and Opera Mobile render the page to the width of 980px, and then shrinks it down to the actual width (320px on old iPhones and 640px on iPhone 4 and 5). By using the meta tag viewport
your Web page overrides this default and renders itself according to the actual device size. All code samples in this chapter include the viewport
meta tag in index.html. All mobile browsers support it even though it’s not a part of the HTML standard yet.
---
<meta name="viewport" content="width=device-width, initial-scale=1.0">
---
This meta tag tels the browser that the width of the virtual viewport should be the same as the width of the display. It’ll will work fine if your responsive design includes a version of the page layout optimized for the width of the user’s device. But if you’d be rendering a page that’s narrower than the default width of the display (e.g. 500 pixels) setting the attribute content="width=500"
would allow the mobile Web browser to scale the page to occupy the entire display real estate. Setting the initial scaling to 1.0 ensures that the page will be rendered as close to the physical device size as possible. If you don’t want to allow the user scale the Web page, add the attribute user-scalable=no
to the meta tag viewport
.
Warning
|
If you’ll apply the initial scale to be 1.0, but to a Web page that was not build using responsive design principles, users will need to zoom or pan to see the entire page. |
Some of the important concepts to take away from this example are to switch from pixels to percentages when specifying width. In the next examples you’ll see how to switch from using rigid px
to more flexible em
units. The CSS float
property you can control relative (not absolute) positioning of your page components.
How many media queries is too many? It all depends on the Web page you’re designing. In the sample CSS shown in this section above we’ve used the breakpoint of 768px to represent the width of the tablet in the portrait mode, and this is fine for the iPad. But several tablets (e.g. 10.1" Samsung Galaxy) have 800px-wide viewport while Microsoft Surface Pro is 1080px wide.
There is no general rule as to how many breakpoint is needed for a typical Web page. But if there is a vieport width when you change the layout of the page, create a breakpoint for this width. Just create a simple Lorem Ipsum prototype of your Web site and start changing its size. If you don’t like how the content looks, you may need to create a breakpoint and define a media query for it.
Tip
|
Use Google Chrome Developer Tools to find out the current width of the viewport. Just type in the console window.innerWidth and you’ll see the width in pixels.
|
Don’t try to create a pixel perfect layout using responsive design. Use common sense and remember, the more different media queries you provide the heavier your CSS file will become. But in mobile world you should try to create Web applications as slim as possible.
Warning: Be prepared to see inconsistencies among the desktop browsers in measuring the width of the viewport. Our tests showed that WebKit-based browsers add about 15px to the width, supposedly accounting for the width of the scrollbar. So if you have a media query that has to change the layout at 768px, it’ll change it at about 783px. Do more testing on different viewports and adjust your CSS as needed.
Fluid grids is a very important technique in the responsive design. Grids were used by Web designers for ages - a web page was divided by a number of imaginary rows and columns. But the fluid grid, as the name implies, is flexible and can scale based on the screen sizes.
When a browser displays text it uses its default font size unless it was overruled by the font-size
property. Typically, the default font size is 16 pixels. But instead of using the absolute font size, you can use the relative one by using so called em units. The default browser’s font size can be represented by 1em. Since the font size happens to be 16px then 1em is 16 px.
The absolute sizes are enemies of the responsive design Web sites, and specifying the sizes in em unit allows you to create Web pages with the pretty flexible and fluid content. The size can be calculated based on a formula offered by Ethan Markotte in his article on fluid grids: target/context=result
, which in case of fonts becomes size-in-pixels/16 = size-in-em
.
For example, instead of specifying the size as 24px, you can set it to 1.5em: 24/16. In your CSS file you can write something like padding-bottom: 1.5em
. This may seem not a big deal, but it is, because if everything is done in relative sizing, your page will look good and proportional regardless of the screen size and regardless of how big or small 24px may look on a particular screen.
If we are talking about em units for representing font sizes, the font becomes the context, but what if you want to represent the width of an arbitrary HTML component in a browser’s window or any other container? Then the width of your component becomes the target
and the total width of the container becomes the context
. We can still use the above formula, but will multiply the result by 100%. This way the width on an HTML component will be represented not in em, but in percentages relative to the total width of the container.
For example, if the total width of the browser’s window is 768px, and we want to create a 120px-wide panel on the left, instead of specifying this width in pixels we’ll use the formula and turn it into percentages.We want to calculate the target’s width in percents of the available context (100%):
120 / 768 * 100% = 15.625%
Such approach makes the page design fluid. If someone decides to open this page on a 480px-wide screen, the panel will still take 15.625% of the screen rather than demanding 120 pixels, which would look substantially wider on a smaller viewport.
While designing your page you can overlay any HTML container or the entire Web page real estate with imaginary grid with any number of columns. Make it flexible though - the width of each column has to be specified in percentages.
Adobe Dreamweaver CS6 automates creation of media queries and it introduced Fluid Grid layout (see Creating a Fluid Grid Layout in Dreamweaver). It also allows you to quickly see how your design will look like on the tablet or phone (you can pick screen size too) with a click on the corresponding status bar button.
Web designers use different approaches in styling with fluid grids. When you design a new page with Dreamweaver’s Fluid Grid Layout it suggests you to allocate different number of columns for desktop, tablet and mobile, for example, its default offer is to allocate 12 columns for the desktops, 8 for the tablets, and 5 for phones, which is perfectly solid approach. But our Web designer Jerry prefers using 12 columns for all screen sizes playing with the width percentages for different layouts - you’ll see how he does it in the project Responsive Donation Section later in this chapter.
Now imagine that you’ll overlay the entire window with an invisible grid containing twelve equally sized columns. In this case each column will occupy 8.333% of the total width. Now, if you’d need to allocate to some HTML component about 40% of the total width, you could do this by allocating five grid columns (8.333% * 5 = 41.665%). Accordingly, your CSS file can contain 12 classes that you can use in your page:
.one-column {
width: 8.333%;
}
.two-column {
width: 16.666%;
}
.three-column {
width: 24.999%;
}
.four-column {
width: 33.332%;
}
.five-column {
width: 41.665%;
}
.six-column {
width: 49.998%;
}
.seven-column {
width: 58.331%;
}
.eight-column {
width: 66.664%;
}
.nine-column {
width: 74.997%;
}
.ten-column {
width: 83.33%;
}
.eleven-column {
width: 91.663%;
}
.twelve-column {
width: 100%;
float: left;
}
Now let’s see the fluid grid in action. Run the Aptana’s project Responsive Fluid Grid and you’ll see the Web page that looks similar to Fluid Grid on the wide screen. This example changes the grid layout if the viewport width falls under one of the following width breakpoints: 768px, 640px, and 480px. In this context the term breakpoints here has nothing to do with debugging - we just want the content of the Web page to be rearranged when the width of the viewport passes one of these values.
If you’ll start lowering the width of the browser’s window, you’ll see how the grid cells start squeezing, but the layout remains the same until the page size will become lower than one of the predefined breakpoints. Then another media query kicks in and the layout changes. For example, Fluid Grid on the viewport under 640px shows the fragment of the Web page when the width of the browser’s window goes below 640px. The 12-, 6-, and 4-cell grids show all the cells vertically one under another. Only the 480px grids still have enough room to display their cells horizontally. But if you keep squeezing the window, all the grids will display their content in one column as long as the viewport width stays under 480px.
The fragment of the index.html from the Responsive Fluid Grid project goes next. For brevity, we’ve removed some repetitive markup and marked such places with the comment "A fragment removed for brevity". This code fragment includes the 12-, 6-, and 4-column grids shown on top of Fluid Grid on the wide screen.
<head>
<meta charset="utf-8">
<title>Responsive fluid grid</title>
<meta name="description" content="Responsive fluid grid example">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div id="wrapper-container">
<h1 class="temp-heading">Responsive fluid grid example</h1>
<h4 class="temp-heading">Breakpoint-768: change float of HTML elements if viewport is 768px or smaller</h4>
<div class="row breakpoint-768">
<div class="one-column cell">
1
</div>
<div class="one-column cell">
2
</div>
<div class="one-column cell">
3
</div>
<!-- A fragment removed for brevity -->
<div class="one-column cell last-cell" >
12
</div>
</div>
<h4 class="temp-heading">Breakpoint-768: change float of the 12-cell grid if viewport is 768px or smaller</h4>
<div class="row breakpoint-768">
<div class="two-column cell">
1
</div>
<div class="two-column cell">
2
</div>
<!-- A fragment removed for brevity -->
<div class="two-column cell">
6
</div>
</div>
<h4 class="temp-heading">Breakpoint-768: change float of the 6-cell grid if viewport is 768px or smaller</h4>
<div class="row breakpoint-640">
<div class="three-column cell">
1
</div>
<div class="three-column cell">
2
</div>
<div class="three-column cell">
3
</div>
<div class="three-column cell">
4
</div>
</div>
Note that some of the above HTML elements are styled with more than one class selector, for example class="one-column cell"
. The entire content of the file styles.css from Responsive Fluid Grids project is shown next, and you can find the declarations of the class selectors one-column
and cell
there. Note the section with media queries in this file.
* {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
-webkit-box-sizing:border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {
display: block;
}
ul li {
list-style: none;
}
.row:before, .row:after, .clearfix:before, .clearfix:after {
content: "";
display: table;
}
.row:after, .clearfix:after {
clear: both;
}
/* Start of fluid grid styles */
.row { // (1)
padding: 0 0 0 0.5em;
background: #eee;
}
.breakpoint-480 .cell, .breakpoint-640 .cell, .breakpoint-768 .cell,
.breakpoint-960 .cell, .no-breakpoint .cell { //(2)
float: left;
padding: 0 0.5em 0 0;
}
.one-column {
width: 8.333%; // (3)
}
.two-column {
width: 16.666%; // (4)
}
.three-column {
width: 24.999%; // (5)
}
.four-column {
width: 33.332%;
}
.five-column {
width: 41.665%;
}
.six-column {
width: 49.998%;
}
.seven-column {
width: 58.331%;
}
.eight-column {
width: 66.664%;
}
.nine-column {
width: 74.997%;
}
.ten-column {
width: 83.33%;
}
.eleven-column {
width: 91.663%;
}
.twelve-column {
width: 100%;
float: left;
}
.right {
float: right;
}
.row.nested {
padding: 0;
margin-right: -0.5em
}
/* --------------- Media queries -------------- */
@media only screen and (max-width: 768px) {
.breakpoint-768 .cell {
float: none; // (6)
width: 100%; // (7)
padding-bottom: 0.5em
}
}
@media only screen and (max-width: 640px) {
.breakpoint-640 .cell { // (8)
float: none;
width: 100%;
padding-bottom: 0.5em
}
}
@media only screen and (max-width: 480px) {
.breakpoint-480 .cell {
float: none;
width: 100%;
padding-bottom: 0.5em
}
}
/*End of fluid grid styles*/
#wrapper-container {
width: 95%;
max-width: 1140px;
margin: 0 auto;
}
/* --- .cell visualisation --- */
.cell {
min-height: 50px;
text-align:center;
border-left: 1px solid #aaa;
vertical-align: middle;
line-height: 50px;
}
.cell .cell:first-child{
border-left:none;
}
/* --- .cell visualisation end --- */
h1.temp-heading, h2.temp-heading, h4.temp-heading {
font-size: 1.4em;
margin: 1em 0;
text-align: center
}
h4.temp-heading {
font-size: 1.1em;
}
p.temp-project-description {
margin: 2em 0;
}
-
Styling grid rows, which are containers for cells.
-
Defining common class selectors (floating and padding) for the cells located in the viewports of any width. Please note the property
float: left;
- it’ll change in the media queries section. -
Dividing 100% of the container’s width by 12 columns results in allocating 8.333% of width per column. Each cell in the 12-column table in our HTML has the
one-column
class selector. -
Check the HTML for the 6-column grid - each cell is styled as
two-column
and will occupy 16.666% of the container’s width. -
The HTML for the 4-column grid uses the
three-column
style for each cell that will use 24.999% of the container’s width. -
This media query turns off the floating if the viewport is 768px or less. This will reallocate the cells vertically.
-
The cell should occupy the entire width of the container as opposed to, say 8.333% in the 12-column grid.
-
The media query for 640px won’t kick in until the viewport width goes below 640px. If you’ll resize the browser window to make it below 768px but larger than 640px, note that the 4-column grid (styled as
breakpoint-640
) has not changed its layout just yet.
Tip
|
In some cases you may need to use a mix of fluid and fixed layouts, for example, you may need to include an image of a fixed size on your fluid Web page. In such cases you can use a fixed width on some of the elements, and if needed, consider using CSS tables (not to be confused with HTML tables). CSS tables are supported by all current browsers. |
Spend some time analyzing the content of index.html and styles.css files from the project named Responsive Fluid Grid. Try to modify the values in CSS and see how your changes affect the behavior of the fluid grid.In the next section we’ll apply these techniques to our Save Sick Child application.
Tip
|
Twitter has developed a framework called Bootstrap, which supports fluid grid system and responsive design. |
First, run any of the previous versions of the Save Sick Child application to make sure it was not responsive. Just make the browser window narrower, and you won’t see some of the page content on the right. We’ll make the page responsive gradually - the first version will make the header responsive, then the donation section, and, finally the entire page will become fluid. Run the Aptana’s project named Responsive Header and you’ll see a page similar to Responsive Header (width 580px+).
Below is the fragment from index.html that’s displays the logo image and the header’s menus.
<div id="wrapper-container">
<header class="row breakpoint-640">
<h1 id="logo" class="four-column cell">
<img src="assets/img/logo.png" alt="Save Sick Child logo"/></h1>
<nav class="eight-column cell">
<ul>
<li>
<a href="javascript:void(0)">Who We Are</a>
</li>
<li>
<a href="javascript:void(0)">What We Do</a>
</li>
<li>
<a href="javascript:void(0)">Where We Work</a>
</li>
<li>
<a href="javascript:void(0)">Way To Give</a>
</li>
</ul>
</nav>
Initially, this code uses the four-column
style (width: 33.332%;
of the container) for the logo and eight-column
(66.664%
) for the <nav>
element. When the size of the viewport changes, the appropriate media query takes effect. Note the breakpoint-640
class selector in the <header>
tag above. Jerry, our Web designer, decided that 640 pixels is not enough to display the logo and the four links from the <nav>
section in one row. Besides, he wanted to fine tune the width of other elements too. This is how the media query for the 640px viewport looks like this:
@media only screen and (max-width: 640px) {
.breakpoint-640 .cell {
float: none;
width: 100%;
padding-bottom: 0.5em
}
header {
margin-top: 1em;
}
#login {
top: 1em;
}
#logo.four-column {
width: 40%;
}
nav {
width: 100%;
margin-top: 0.8em
}
nav ul li {
width: 24.5%;
margin-left: 0.5%
}
nav li a {
text-align: center;
font-size: 0.6em;
}
#login-link-text {
display: none;
}
a#login-submit {
padding: 0.2em 0.5em
}
#login input {
width: 9em;
}
}
As you see, if the cell
has to be styled inside breakdown-640
, the float gets turned off (float: none;
) and each of the navigation items has to take 100% of the container’s width. The logo
, login
, and nav
elements will change too. There is no exact science here - Jerry figured out all these values empirically.
Start slowly changing the width of the viewport, and you’ll see how the layout changes. The styles.css of this project has media queries for different viewport sizes. For example, when the page width is below 580 pixels, but more than 480 pixels it’ll look as in Responsive Header 2 (width between 480 and 580px ).
When the width shrinks to 480px, the header looks as in Responsive Header (width below 480px).
The next version of the Aptana project to try is called Responsive Donation. This version make the donation section fluid. The donation section contains the Lorem Ipsum text and the form, which is revealed when the user clicks the button Donate. First, let’s look at the HTML. The index.html contains the following fragment (some of the content that irrelevant for layout was removed for better readability):
<div id="main-content" role="main">
<section id="main-top-section" class="row breakpoint-480">
<div id="donation-address" class="seven-column cell">
<p class="donation-address">
Lorem ipsum dolor sit amet </p>
<button class="donate-button" id="donate-button">
<span class="donate-button-header">Donate Now</span>
</button>
</div>
<div id="donate-form-container">
<h3>Make a donation today</h3>
<form name="_xclick" action="https://www.paypal.com/cgi-bin/webscr" method="post">
<div class="row nested breakpoint-960">
<div class="six-column cell">
<div class="row nested">
<div id="donation-amount" class="five-column left">
<label class="donation-heading">Donation amount</label>
<input type="radio" name="amount" id="d10" value="10"/>
<label for="d10">10</label>
</div>
<div id="donor-info" class="five-column left">
The donation section is located in the main-top-section
of the page. Jerry wanted to keep the image of the boy visible for as long as possible on the narrower viewports. The top section of the Save Sick Child has two backgrounds: the flowers (bg-2.png) and the boy (child-1.png). This is how they are specified in the style.css:
#main-top-section {
background: url(../img/child-1.png) no-repeat right bottom,
url(../img/bg-2.png) no-repeat 20% bottom;
}
If the viewport is wide enough, both backgrounds will be shown. What’s wide enough? Jerry figured it out after experimenting. The seven-column
style prescribes to allocate more than a half (58.331%) of the viewport width for the donation-address
section and six-column
(49.998%) for the donation form. For example Responsive Donate Section: 570px shows how the donation section will look when the viewport width is 570px.
But when the width become less then 480px, there is no room for two background images, and only the flowers will remain on the page background. The media query for 480px viewport is shown next - note that the background in the main top section has only one image now: bg2.png. Floating is off to show the navigation menu vertically as in Responsive Donate Section under 480px.
@media only screen and (max-width: 480px) {
.breakpoint-480 .cell {
float: none;
width: 100%;
padding-bottom: 0.5em
}
#logo {
padding-bottom: 11em
}
nav ul li {
float: none;
width: 100%;
margin-left: 0;
margin-bottom: 0.5%;
}
#main-top-section {
background: url(../img/bg-2.png) no-repeat 20% bottom;
}
.donate-button {
width: 14em;
margin-left: auto;
margin-right: auto;
}
.donate-button-header {
font-size: 1.1em;
}
.donate-2nd-line {
font-size: 0.9em;
}
#donate-later-link {
display: block;
width: 11em;
margin-left: auto;
margin-right: auto;
}
#make-payment p {
width: 100%;
}
#donation-amount.five-column {
width: 50%
}
#donor-info.six-column {
width: 50%
}
#donate-form-container select, input[type=text], input[type=email] {
width: 90%;
}
}
The Aptana project Responsive Final includes the charts, maps, and video. Each of these sections uses four-column
style, which is defined in styles.css as 33.332% of the container’s width.
<section id="main-bottom-section" class="row breakpoint-768">
<div id="charts-container" class="four-column cell">
<svg id="svg-container" xmlns="http://www.w3.org/2000/svg">
</svg>
<h3>Donation Stats</h3>
<h5>Lorem ipsum dolor sit amet, consect.</h5>
</div>
<div id="map-container" class="four-column cell">
<div id="location-map"></div>
<div id="location-ui"></div>
</div>
<div id="video-container" class="four-column cell last">
<div id="video-wrapper">
<video id="movie" controls="controls" poster="assets/media/intro.jpg"
preload="metadata">
<source src="assets/media/intro.mp4" type="video/mp4">
<source src="assets/media/intro.webm" type="video/webm">
<p>Sorry, your browser doesn't support the video element</p>
</video>
</div>
<h3>Video header goes here</h3>
<h5><a href="javascript:void(0);">More video link</a></h5>
</div>
</section>
The id of this section is still main-bottom-section
, and it’s shown at the bottom of the page on wide viewports. Now take another look at the image The tablet layout (portrait) implemented. Jerry wants to display these three sections at the right hand side for tablets in the portrait mode, and it’s shown on The Portrait Mode on Tablets.
The relevant code from the style.css is shown below.The top and bottom sections get about a half of the width each, and the floating is turned off so the browser would allocate charts, maps, and video vertically.
@media only screen and (max-width: 768px) {
.breakpoint-768 .cell {
float: none;
width: 100%;
padding-bottom: 0.5em;
}
#main-bottom-section, #main-top-section {
width: 49%;
}
If you responsive Web page contains images or videos, you want to make them fluid too - they should react to the current size of the containers they are in. Our page has a chart image and a video - both of them are made flexible, but we use different techniques.
If you’ll keep narrowing the viewport, the project Responsive Final will show the page with the layout similar to The smaller phone layout (portrait) implemented. While reading the code of this project, visit the main.js file. There is some work done in the JavaScript too, which listens to the resize event for the charts container.
window.addEventListener("resize", windowResizeHandler);
function windowResizeHandler() {
drawPieChart(document.getElementById('svg-container'),
donorsDataCache, labelsDataCache);
}
Whenever the size changes, it invokes the function drawPieChart() that recalculates the width of the SVG container (it uses the clientWidth
property of the HTMLElement
) and re-draws the chart accordingly.
The video is flexible too, and it’s done a lot simpler. We do not specify the fixed size of the video, but use a CSS property width
instructing the browser to allocate the 100% of the available container’s width. The height of the video must be be automatically calculated to keep the proportional size.
video {
width: 100% !important;
height: auto !important;
}
The !important
part disables regular cascading rules and ensures that these values will be applied overriding more specific width or height declarations, if any. If you prefer not always use the entire width of the container for the video, you can use the max-width: 100%;
, which will display the video that fits in the container at its original size. If a video is larger than the container, the browser will resize it to fit inside the container.
Authors of this book have different opinions about the merits of responsive design. One of us simply stated, "I haven’t seen complex single-code-base applications that work well on Android, iPhone, and desktop browsers". The other responded "We need to compromise". With browser plugins like Flash Player or Silverlight you can choose pixel-perfect design. Just set a pre-requisite: the user must have a 1024x768 viewport minus chrome and margins. But if you’ll need to make this application work on highly fragmented Android market, on all iPhones, Blackberies, desktops, and other devices, ask yourself a simple question, "Do we have money to hire two or three teams for developing and supporting several versions of the application for different devices or we’d rather compromise, and push the HTML5-based product out the door?"
Each enterprise project has a limited budget, and if you’ll agree to compromise and move away from the pixel-perfect world accepting the fact that the Donate button will look a little bit different on different devices, go with the responsive design principles and have one code base. You’ll provide different CSS sections that will automatically apply different layouts based on the viewport size, and the HTML markup and JavaScript will be the same. This approach has drawbacks because some portions of unnecessary CSS will be loaded to the user’s device, but this still can be a practical business solution.
On the other hand, using the same code and design for different platforms works perfectly only for publishing information and not for all Web applications. If you need to publish the information using different layout managers, responsive design is a good fit. Mobile applications could be compiled either into the native code or into some byte code that performs close to the native one. But the UI could be different based on the available screen real estate and use touch interface.
If you’ll take any framework that works on both desktop and mobile devices, you’ll get two sets of controls and the need to maintain two different source code bases. Not using mobile JavaScript frameworks limits the number of user-friendly UI controls, Besides frameworks spare you from dealing with browsers incompatibilities.
In this chapter you’ve seen how the Save Sick Child application (not a publishing site) was built with responsive design principles. We have several areas (<div>'s
) and one of them include a donation form (we could have added the responsive <div>
with the online auction too). On the wide screen we displayed three of these <div>'s
horizontally and two underneath, on the narrow screen each of these sections could scaled down and displayed one under another.
But using responsive design for styles application that must run on a tablets or mobile devices will require Jerry-the-designer to work in tandem with the User Experience specialist so that UI will have larger controls and fonts, minimize the need of manual data entry. And don’t forget that half of the mobile screen could be covered by a virtual keyboard, and if you ignore this, the user will have to work with your UI via a keyhole, and even our fluid <div>'s
may not fit.
In the next two chapters we’ll be working on yet another version of Save Sick Child. First, it’s going to be done with the jQuery Mobile framework and then with Sencha Touch.