Zoom-on-rotate fix for WebKit mobile browsers (Mobilizing websites with responsive design and HTML5 part 8)

This blog post is a part of Mobilizing websites with responsive design and HTML5 tutorial. For all posts please see the Introduction post.

After adding meta viewport tag for your mobile site its width is properly formatted for mobile browsers. However, there exists a common glitch you should be aware of.

On iOS devices, and on some Android devices, the mobile browser re-zooms the web page when the device orientation changes. The browser applies heuristics and try to determine a new zoom level after the rotation, but sometimes the result is not desirable. When you rotate from the portrait mode to the landscape mode, the page zooms in too much.

In our case, the project client specifically requested to disable this little feature if possible, as it was irritating the test users on iPad devices.

This can be worked around by resetting the viewport with Javascript after the orientation changes.

An example code going into HTML <head> section:

  <!--

    Don't break scale on iPad rotate.

    By default iPad re-zooms the page when the device orientation changes.
    The heuristics here do not work always; our page got zoomed in
    though it should be max zoomed out.

    This snippet fixes the situation so that you can still zoom in, but when
    the device is rotated the scale is restored.

   -->
<script type="text/javascript">
(function(doc) {

    var addEvent = 'addEventListener',
        type = 'gesturestart',
        qsa = 'querySelectorAll',
        scales = [1, 1],
        meta = qsa in doc ? doc[qsa]('meta[name=viewport]') : [];

    function fix() {
        meta.content = 'width=device-width,minimum-scale=' + scales[0] + ',maximum-scale=' + scales[1];
        doc.removeEventListener(type, fix, true);
    }

    if ((meta = meta[meta.length - 1]) && addEvent in doc) {
        fix();
        scales = [.25, 1.6];
        doc[addEvent](type, fix, true);
    }

}(document));
</script>

Please edit the scales part of the code for the desired min and max scaling level.

Note: Dynamic viewport manipulation is badly supported on older Android devices and contains many pitfalls.

More info

 Subscribe to this blog in a reader Follow me on Twitter

Improving mobile site form usability with HTML5 (Mobilizing websites with responsive design and HTML5 part 7)

This blog post is a part of Mobilizing websites with responsive design and HTML5 tutorial. For all posts please see the Introduction post.

It is cumbersome to enter any longer input on mobile devices with “thumb typing”.

For better mobile user experience you want to optimize form inputs to have minimal amount of presses.  Also, the form layout might need adjustments to cope with the smaller screen size and harder-to-read text.

In the case we describe in this tutorial, we use mobile.css to override the default desktop form styles so that the form renders and acts better on small screens and touch devices.

Making forms more mobile friendly

Some useful mobile enhancements include

  • Make text bigger: Text and <input> field default size is bigger, so that you don’t need to zoom in to read the label.
  • Use fixed width font on input fields: Fixed width fonts, like Courier, are cleaner for reading narrow letters, like i,1,l on small input fields. It may look ugly, but it’s minor usability win.
  • Only one column of form elements: There is only one column on <input> and no <form> elements are horizontally on the same row, so that there is as much as possible horizontal text line length to be consumed for <input> fields. Exception: make sure that checkbox control + label still remain on the same row.
  • Expand controls to full screen width: easier to hit with touch and there is enough space to read the input field values
  • More padding and margin for form controls to help touch input by avoiding accidentally presses
  • Use field type specific HTML5 inputs: more below
  • Use Javascript to enhance form input logic: e.g. automatically choose sane defaults based on other field values or submit the form when it’s completed, so that the user spends less time to enter the data on the form
  • Use geolocation to pre-fill address fields and filter out lists of unnecessary choices

Here are some example mobile.css styles which we used for mobilizing forms desktop forms:

/*
 * Form fixes
 */

/* Only one input per row */
select, input, button {
   display: block;
   margin-bottom: 1em;
   max-width: 80%;
   font-size: 120%;
}

/* Follow the size of input elements */
label {
   font-size: 120%;
}

/* Checkbox is still inline */
input[type=checkbox] {
    display: inline;
}

How forms looked before fix:

How forms looked after the fix:

Short-cutting unnecessary user choices

In our project we also applied a Javascript snippet which will automatically submit the form when the final <select> input choice has been made. Thus, the user does not need to pan around to press the form submit button unnecessarily: this way we decrease the amount of presses needed to proceed with the form.

The Javascript code for the form autosubmission:

<script type="text/javascript">

  // Automatically push form forward when the selection has been
  // made in the selection list
  function onSelect() {
     var form = document.getElementById("IdPList");

     if(form) {
         form.submit();
     }
  }

  // Bind select event handler
  function init() {
 var select;

     // Remember selection permanently and bypass the WAYF service from now on.
     select = document.getElementById("select-idp");

     if(select) {
         select.addEventListener("change", onSelect);
     }

     // Select: In order to access the resource you must authenticate yourself.
     select = document.getElementById("userIdPSelection");

     if(select) {
         select.addEventListener("change", onSelect);
     }
  }

  //window.addEventListener("DOMContentLoaded", init);
  window.addEventListener("load", init);
</script>

HTML5 <input> element enhancements

It is also recommended to convert <input type=text> fields for HTML5 specific versions. Note that this change is backward compatible, as the legacy browsers will fallback to normal text input. Even big sites like Amazon.com are already using HTML5 inputs. With specific HTML5 input types a mobile browser can open a field type specific touch keyboard. E.g. if you are asking for a phone number the opened keyboard is phone keypad instead of QWERTY touch keyboard.

Different <input> types already exists for

  • Telephone number
  • Email
  • IP address
  • URL
  • Number
  • Search
  • Time
  • Native autocomplete
  • etc.

Geolocation

You can use HTML5 geolocation API to determine the city / address of the user and pre-fill form values based on this. This is handy e.g. on a use cases like where the user is selecting city to choose a movie theaters.

jQuery Mobile

jQuery Mobile is a theming framework for mobile sites. It includes some touch friendly Javascript widgets to enhance existing mobile experience. However there widgets are more theming side of the things and the necessary user interaction can be reached even without jQuery Mobile.

File submissions

iOS devices, like iPhone and iPad, do not support <input type=file> file submissions (iOS 5.0). Android devices do and other mobile phones as well. However, the user experience of selecting files on these devices is not great and you might want to create an app instead.

More information

 

 Subscribe to this blog in a reader Follow me on Twitter

Resizing images in responsive mobile design (Mobilizing websites with responsive design and HTML5 part 6)

This blog post is a part of Mobilizing websites with responsive design and HTML5 tutorial. For all posts please see the Introduction post.

When you change your layout dynamically you need to re-fit media elements to match the new layout dimensions. There exist three basic techniques dealing with images in responsive designs

  • Resizing images using CSS only  – in this case the clients download the full image payload regardless of the image size and image visible sizes are adjusted using CSS styles
  • Co-operative image resizer on the front end web server: when HTML is written from a template the image tags are written in such a way that <img src> attribute points to a resized image. The resizer rewrites image to match the vrowser screen dimensions. This is done e.g. in Web and Mobile for Plone CMS.
  • Independent image resizer on the front end web server: Javascript + server-side stub component is used to resize the images. The server-side component does not depend on the rest of the front-end server system, thus making the front end code less complex. A client-side Javascript scans HTML DOM tree for <img> tags and rewrites <img src> to go through the resizer. For example Adaptive Images (below) is this kind of a solution. Alternatively, an independent image resizer can be a part of the middleware stack (e.g. WSGI in Python)

In this blog post we mostly discuss about the simplest approach: resizing images using CSS only.

Resizing images using pure CSS

If your responsive layout includes images, as contentish or style elements, they might not work well with small screens as is. You can fix the situation by resizing the images dynamically with CSS.

In our example case the page has only one image: the site logo. If viewed in a mobile browser using desktop CSS the logo might be too small or too large. Thus

  • We remove any hard-coded width and height values for the <img> in HTML
  • We apply CSS style for the image width where the image takes width from the screen width as percents, but still has max-width set in pixels so that tablet devices with more screen estate don’t scale the image too much

Related CSS:

/* Logo must not appear too large on mobile */
#portal-logo img {
   width: 33%;
   max-width: 180px;
}

Before fix:

After fix:

Server-side image resizing solutions

You can also resize images dynamically on the server-side, so that mobile browsers load the reduced size version, saving the precious mobile bandwidth. However, this adds additional server-side component to the mix, increasing the complexity of the solution and especially when dealing with legacy sites consider whether the improved user experience is enough to balance this trade-off.

Also, the dynamic image resizer component is easily subject to denial of service attack because the HTTP responses it serve are usually slow and computationally intensive. If you decide to use one of these components be sure you are aware of these implications.

You don’t need to change the server-side generated HTML to achieve the dynamic images sizes. There exist a technology neutral solutions relying on the client-side Javascript and additional serve-side proxy component.

Adaptive Images is one of server-side image resizing solutions based on Javascript and minimal server-side PHP script. It operates in independent manner and adheres the contemporary best practices of HTML5 and responsive web designs.

 Subscribe to this blog in a reader Follow me on Twitter

Mobile site CSS with CSS3 media queries (Mobilizing websites with responsive design and HTML5 part 5)

This blog post is a part of Mobilizing websites with responsive design and HTML5 tutorial. For all posts please see the Introduction post.

To mobilize the legacy website, we create a responsive design with two layout steps: desktop and mobile. We use a separate mobile.css stylesheet which will override legacy desktop styles for mobile browsers with more suitable variations for small screens.

CSS3 Media queries are a method of selectively loading CSS stylesheets based on various criteria like screen size and orientation. They are supported by all state-of-the-art mobile and desktop browsers.

mobile.css stylesheet

  • is loaded for mobile devices only using CSS3 media queries
  • when developing, we force the file to be loaded on our development browser (Firefox + Firebug) simply by removing the media query condition in the stylesheet HTML tag

Defining the media query to discriminate mobile devices

The media query uses simple screen pixel count to determine whether the screen is “small” or not. Though CSS3 has rapidly advanced, it still cannot answer the basic question “what is the diameter of the screen in physical inches”, the only information which we would be interested in. Thus, some heuristics are required to guess whether the screen is actually small or not… hopefully we’ll see some kind of pixel size + DPI or diameter in inches selectors in the future CSS media queries to make hacks unnecessary.

Note: In the case related to this tutorial, the client wanted the tablet browsers to receive mobile styling also. This improved touch screen accessibility, though the tablet browsers usually work well with desktop layouts too.

Note: Media queries determine the screen width by the device orientation and you can have different CSS loaded depending whether the device is in portrait or landscape orientation mode.

Note: Browsers report their screen width in heterogeneous manner. Whether reported widths are the virtual screen width in virtual pixels or the real pixel width may vary browser by browser. See notes below.

Note: WebKit has a WebKit specific media query selector called -webkit-device-pixel-ratio which tells ratio between physical and virtual pixels. It is designed to discriminate high DPI mobile screens, which are wider than 640 pixels but still in small form factor.

CSS3 media query linking code for loading the mobile.css stylesheet in HTML <head>:

   <!--
     Detect mobile devices + iPad.

     High DPI smart phones report "virtual" pixels here which is usually 1/2 x normal pixels.
     E.g. iPhone 4 with 960 px wide screen reports 480 pixels.
     We use 500 px as the threshold.

     We cut out devices at 900 pixels wide, so 1024 px desktop screens are not included.

   -->

   <link rel="stylesheet" media="screen and (max-device-width: 900px)" href="css/mobile.css" />

   <!--

     This is for Android.

     Android Browser HPDI screens uses actual pixels max-device-width and
     they are indistinguishable from iPad. The screen can have max-device-width=768
     which is also the value for tablets.

     Here we simply use WebKit HDPI screen "virtual pixel" aspect ratio detector
     to see if we are using virtual pixels. If we are then assume a mobile screen.

   -->

   <link rel="stylesheet" media="screen and (-webkit-device-pixel-ratio: 1.5)" href="css/mobile.css" />

To test the mobile styles in a deskto browser simply remove media condition from <link> code.

The project page before mobile CSS was applied:

The page after mobile CSS has been applied:

Much better!

Note: Older mobile browsers might not support CSS3 media queries. They will simply fallback to the desktop version of the site CSS, no harm done.

Resetting desktop styles

The most important task for the mobile.css to do is to reset the website width and main content wrapping from the hardcoded centered column to something spreading across the whole mobile screen width.

Here are some example styles we applied in mobile.css to drop hardcoded width values and adjust margins to more suitable values. As you can see we use !important CSS directive to override many desktop styles – if your site is using several CSS files or complex style hierarchies this switch might be needed to make sure styles are overridden properly.

/* Disable background image */
body {
    background: white !important;
}

/* Fill entire mobile viewport width - don't force hard pixel widths*/
#visual-portal-wrapper {
    width: 100% !important; /* Was width: 960px */
    margin: 0;
}

#main-margin {
     margin: 0;
}

/* Mobile footer cannot be fixed height as it may layout as many rows
   instead of one */
#footer2 {
    width: 100% !important;
    margin: 0;
    padding: 0;
    height: auto; /* Was 60px */
}

/* Fix footer margins */
#footer-wrapper {
    padding: 10px 20px 0 20px;
}

/* Make two footer elements reactive and lay from top to bottom on too narrow screen */
#footer-wrapper > div {
   display: block;
   float; left;
}

#footer-wrapper > a {
   width: 120px;
}

More information

 Subscribe to this blog in a reader Follow me on Twitter