BYOD stands for Bring Your Own Device. It became a new trend - many enterprises started allowing their employees to access corporate applications from personal tablets or smartphones. CYOD stands for Choose Your Own Device - corporations let their employees to choose a device that belongs to the enterprise. Developers of new Web applications should always think of the users that will try to run this application on a mobile device. This part is about various strategies of developing Web applications that look and perform well not only on the desktop computers but on a smaller screens too.
In this chapter we’ll explain what the Responsive Design is and how you can build an HTML5 application that will have a single code base for desktops, tablets and smartphones. We’ll apply the Responsive Design principles and re-design our Save The Child application to have fluid layout so it’ll remain usable on smaller screens too.
Another approach is to have separate versions of the application for the desktops and mobile devices.Chapter 11 and 12 will demonstrate how to create dedicated mobile versions of Web application with jQuery Mobile library and Sencha Touch framework respectively. And the Save The Child application will get re-written in each of these chapter.
Finally, in Chapter 13 will talk about yet another approach for developing HTML5 applications for mobile devices - so called hybrid applications. These are the applications that are written in JavavaScript, but are packaged as native apps. You’ll learn how Adobe’s PhoneGap can package an HTML5 application to be accepted in online stores where native applications are being offered. To illustrate accessing hardware features of a mobile device we’ll show you how to access a photo camera of the mobile device - this can be a useful feature for the Save The Child application.
Up till now we’ve been writing and re-writing the desktop version of the Save The Child application. Will it look good on the small screen of a mobile device? Starting from this chapter we’ll deal with the mobile devices too.
Let’s discuss different approaches to developing a Web application that can work on both desktop and mobile devices. There are three choices:
-
In addition to your Web application that works on desktops develop a separate version of the native applications for multiple mobile devices. Development of native mobile applications is not covered in this book.
-
Develop a single HTML5 Web application, but create several different UI layouts that will be applied automatically based on the screen size of the user’s device.
-
In addition to your Web application that works on desktops develop a hybrid application, which is a Web application on steroids - it works inside the mobile browser, but is packaged as native app and can invoke native API of the mobile device too. Chapter 13 is dedicated to hybrid applications.
This chapter is about the second approach called Responsive Design. This term was coined by Ethan Marcotte in 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 The Child site to introduce different layouts for the desktop, tablet, and smart phones. By the end of this chapter the site Save The Child will automatically change its layout (without the losing functionality) based on the screen size of the user’s device.
Run any of the versions of our Save The Child from the first chapters of the book 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 - those layouts of the Save The 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 The 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 as in Non-responsive version of the app on iPhone 5. Such design of the Save The 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 a Web site a specifically designed for smartphones? It’s so easy! Just press the button and enter the email of the person to share the site with. Many mobile Web sites shared this way won’t look pretty on the large screen. It may just show the wider version of what you see in your mobile screen.
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 The 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 The 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, four, six, or twelve 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 if you put all your media queries in the same CSS files, 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.
You can have several CSS files for different devices. Include these files using the media attributes. But Web browsers are not smart enough to selectively download only those CSS that are needed. For example, the following HTML will load both CSS files on any user’s device:
<link media="only screen and (max-width: 480px)" href="css/smartphone.css"rel="stylesheet">
<link media="only screen and (max-width: 768px)" href="css/tablet.css"rel="stylesheet">
Tip
|
Using the Window.matchMedia attribute may allow you to conditionally load CSS in JavaScript.
|
Note
|
Consider combining Responsive Design on the client with some device-specific components (a.k.a. RESS) optimization on the server. |
Important
|
While Responsive Design allows to re-arrange the content based on the screen size, it may not be a good idea to show the same amount of content on desktop and smartphones. Making a Web application look good on mobile devices must involve not only Web designers and developers, but also people who are responsible for content management. |
Note
|
Consider combining Responsive Design on the client with some device-specific components (a.k.a. RESS) optimization on the server. |
Important
|
While Responsive Design allows to re-arrange the content based on the screen size, it may not be a good idea to show the same amount of content on desktop and smartphones. Making a Web application look good on mobile devices must involve not only Web designers and developers, but also people who are responsible for content management. |
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 iPhone 5 is reported and explained by useragentstring.com. But this information might become unreliable after iOS upgrades.
There is an easier way to detect on the server that the request came from a mobile device. Wireless Universal Resource File (WURF) is a database of thousands of supported devices and their properties. Such Internet giants as Facebook and Google rely on this service and your application could too, if need be. WURF offers APIs from several programming languages to detect specific capabilities of the user devices. For example, the following code snippet is how you could access the WURF data from a Java servlet.
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
WURFLHolder wurfl = (WURFLHolder)getServletContext()
.getAttribute(WURFLHolder.class.getName());
WURFLManager manager = wurfl.getWURFLManager();
Device device = manager.getDeviceForRequest(request);
log.debug("Device: " + device.getId());
log.debug("Capability: " + device.getCapability("preferred_markup"));
It’s impossible to create different layouts of a Web application for thousands of user agents. Market fragmentation in the mobile world is a challenge. People are using 2500 different devices to connect to Facebook. Android market is extremely fragmented. The Figure Android Device Fragmentation is taken from the report Android Fragmentation Visualized (July 2013) by Open Signal.
Of course, device fragmentation doesn’t equal Android OS version fragmentation, but this situation is similar to the challenge that Microsoft was always facing - making sure that Windows works fine on thousands different types of hardware. It’s not an easy job to do. In this regard Apple is in much better position because they are the only hardware and software vendor of all devices running iOS.
It’s great for the consumers that Android can be used on thousand devices, but what about us, the developers? Grouping devices by screen sizes may be 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 these main pillars:
-
CSS media queries
-
Fluid grids or fluid layouts
-
Fluid media
Note
|
Typography can be also considered as one of the pillars of the responsive design. This subject belongs to publications written for Web designers and will not be covered in this book. Oliver Reichenstein’s article Responsive Typography: The Basics is a good introduction to this topic. |
Media query is a CSS element. It consists of a media type (e.g. @media (min-width: 700px) and (orientation: landscape)) followed by the styles applicable to this media. Media queries allow to rearrange the sections (`<div>’s') of the page based on the screen size, fluid grids allows to properly align and scale the content of these sections, and the fluid media is about resizing images or videos.
Data grid components are often included in enterprise applications. Fluid grids are designed using relative positioning and can scale based on the screen sizes. Fluid media is about creating videos and images that react to the screen sizes. We’ll talk about the above pillars in greater details later in this chapter. 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 The 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 versions 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. iPhone 3 falls into this category.
If need be, you can ask Jerry to create mockups for the real 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 the project titled Responsive_basic_media_queries, and it’ll look as in The desktop layout implemented. This is a 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.
The W3C Recommendation titled Media Queries has been introduced in CSS2 and HTML4. The idea was to provide different stylesheets for different media. For example, you can specify different stylesheets in HTML using the media
attribute for the screens that are less than 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)">
You may have several of such <link>
- tags for different screen widths. But all of them will be loaded regardless of the actual size of the user’s display area. The modern browser may defer loading of the CSS files that don’t match the current display size.
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 or tv
for TV devices. For the up to date list of media types see the document Media Queries W3C 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 The Child is not a publication so we keep its maximum width within 1140px. Or you may decide to make a version of Save The 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 tells 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.
Tip
|
Install an Add-On for Google Chrome called Window Resizer. It’ll add an icon to the toolbar for easy switch between the browser screen sizes. This way you can quickly test how your Web page looks on different viewports. There is another handy Add-On for Chrome called Responsive Inspector, which allows you to see the various media queries for a page and automatically resize to them. |
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. Let the content of your page (and where it breaks) dictate where you add breakpoints. Just create a simple Lorem Ipsum prototype of your Web site and start changing its size. At a certain point (viewport size) your design starts to break. This is where you need to put your breakpoint and define a media query for it. It is recommended to start with designing for the smallest viewports (the "Mobile First" principle). As the viewport width increases you may decide to render more content hence define a new breakpoint. Technically this means that the content of your CSS should default to the smaller viewports and only if the screen is larger, apply media queries. Such approach will reduce the CSS handling by the browser of the mobile device (no need to switch from large to smaller layouts).
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.
Let’s say 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.
Tip
|
Adobe’s Creative Cloud includes a tool called Edge Reflow, which will help designers in creation of responsive Web pages. |
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 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 The Child application.
Tip
|
There are several responsive frameworks that offer CSS, typography and some JavaScript to jump start the development of the UI of a Web application. The Foundation 4 framework promotes mobile first design and includes the flexible grid. Consider using Twitter’s framework called Bootstrap, which has lots of greatly styled components and also supports fluid grid system. The Skeleton is a collection of CSS files, which includes a scalable grid. |
First, run any of the previous versions of the Save The 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. Open in the Web browser the file index.html from the 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 The 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 of the viewport shrinks below 480px, the header’s content rearranges and looks as in Responsive Header (viewport’s width below 480px). Once again, we are not tying the design to the specific device, but rather to a viewport width. The iPhone 4 will render this page using the layout shown at <<>FIG11-16>, but iPhone 5 will use the layout from Responsive Header 2 (width between 480 and 580px ). You can’t go by a device type.
The next 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 The 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 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%;
}
Note
|
We’ve explained the use of media queries for applying different styles to the UI based on screen resolutions. But there is a twist to it. What device comes to mind if you hear about the screen with the resolution of 1920x1080 pixels? Most likely you got it wrong unless your answer was the smartphone Galaxy S4 or Sony Xperia Z. The resolution is high, but the screen size is 5 inches. What media query are you going to apply if the user has such a device? Even with such high resolution you’d rather not apply the desktop’s CSS to such a mobile device. The CSS media query device-pixel-ratio may help you in telling apart high-resolution small devices from desktops. |
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.
Tip
|
Consider storing images in the WebP format, which is a lossless format, and WebP images are about 25% less in sizethan PNG or JPEG images. Your application needs to check first if the user’s Web browser support WebP format, otherwise images in more traditional formats should be rendered. The other choice is to use Tumbor imaging service that can automatically serve WebP images to the browsers that support this format. |
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.
While the landing Web page of your application simply includes links to the required images, the rest of the images should be loaded from the server by making AJAX requests with passing parameter regarding the viewport size. This way the server’s software can either resize images dynamically and include them as base-64 encoded strings or use pre-created properly sized images depending on the viewport dimensions.
Tip
|
While using base-64 encoding increases the total size of the image in bytes, it allows you to group together multiple images to minimize the number of network calls the browser needs to make to retrieve these images separately. The other way to combine multiple images into one is CSS sprites. |
Regardless of what the width and height of the image is, use tools to reduce image sizes in bytes. Some of such tools are TinyPNG or Smush.it. If you use lossy tools, some of the image data will be lost during compression, but in many cases the difference between the original and compressed image is invisible.
Tip
|
Sencha.io SRC is a proxy server that allows you to dynamically resize images for various mobile screen sizes. |
Besides making images responsive, keep in mind that some people have mobile devices with high resolution retina displays. The problem is that to make an image look good on such displays its size has to be large, which increases its loading time. There is no common recipe for doing the image size optimization properly - plan to spend an extra time just to preparing the images for your application.
There is a living W3C document titled An HTML extension for adaptive images that will provide developers with a means to declare multiple sources for an image. The proposed HTML element <picture>
will allow to specify different images for different media (see demos), for example:
<picture width="500" height="500">
<source media="(min-width: 45em)" src="large.jpg">
<source media="(min-width: 18em)" src="med.jpg">
<source src="small.jpg">
<img src="small.jpg" alt="">
</picture>
Another technique is to have a CDN that caches and serves images of different sizes for different user agents. The very first time when a request is made from a device with an unknown user engine, this first "unlucky" user will get an image with a low resolution, and then the application makes an AJAX call passing the exact screen parameters for this device. The CDN server resizes the original high-resolution image for this particular user agent, and caches it, so any other users having the same device will get a perfectly-sized image from the get go.
Tip
|
Imager.js is an alternative solution to the issue of how to handle responsive image loading, created by developers at BBC News. Imager loages the most suitable sized image and does it once. |
Responsive Web design is not a silver bullet that allows using a single code base for all desktop and mobile versions of your HTML5 Web application. RWD can be the right approach for developing Web sites that mainly publish information. It’s not likely that you can create a complex single-code-base Web application that works well on Android, iPhone, and desktop browsers.
Responsive design may result in unnecessary CSS loaded to the user’s device. This consideration is especially important for mobile devices operating on 3G or slower networks (unless you’ll find a way to lazy load them).
Responsive design can still can be a practical business solution when the form factor is relatively low (which enterprise can mandate), e.g. if your target group of user operate specific models of iOS and Android devices.
If you’ll take any JavaScript framework that works on both desktop and mobile devices, you’ll get two sets of controls and will have to maintain two different source code repositories. 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 The Child application was built with responsive design principles. We have several areas (<div>'s
) and one of them included 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 styling the application that must run on 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 while minimizing the need of manual data entry. And don’t forget that the half of a mobile screen could be covered by a virtual keyboard, and if you ignore this, the user will look at your application’s 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 the Save The Child application. First, it’s going to be done with the jQuery Mobile framework and then with Sencha Touch.