C/C++ Guides

Home

JavaScript/HTML5 Cross-Platform User Interfaces

These developer guidelines provide a brief overview of what should be considered when creating HTML5 (or hybrid HTML5/C++) MoSync apps that should be used on devices with varying screen sizes.

Prerequisites and preparations

This overview considers a typical MoSync HTML5 based app. Although there is nothing to stop you from importing your own framework for cross platform HTML5 based apps, for this overview we use the WormholeDemo example provided with the MoSync download. That example already has most of what you need already in place.

The WormholeDemo example shows you how to use jQuery and jqTouch to style the app with native looking graphical elements. It also shows how to use different style sheets depending on which platform is being run. This may be extended to include screen size and whether the device is tablet. (To learn the inner workings of this, see the embedded script of the project's index.html file) 

To import WormholeDemo, start the MoSync IDE and follow the instructions here: ../../../../../sdk/tools/guides/ide/importing-example-applications/index.html.

Get your units straight

The proliferation of screen sizes, device types and web clients pushes cross platform enabled web pages into using relative units instead of absolute units. (Google 'responsive web design' for more info.)

One commonly used unit is px, or CSS pixels. CSS pixels is not physical pixels. CSS pixels is the number of 'pixels' that is reported by the web browser. It may happen to be the number of physical pixels, but often its not:

  • Zooming a web page will obviously not change the number of physical pixels. But the number of CSS pixels will change. Doing a 2x zoom will half the CSS pixel width and height of the device.
  • For HTML5 based user interfaces, you will often want to disable zooming to make your app look less browser-based. To do this, add this line to the MyMoblet constructor of main.cpp in WormholeDemo just right after the call to extractFileSystem:
getWebView()->disableZoom();

Some devices reports the number of CSS pixels as the number of physical pixels divided by a device-specific pixel ratio. For example, the iPhone 3 has 320 physical pixels, and a full screen web view has 320 CSS pixels on this device. However, the 640 pixel retina display will still report 320 CSS pixels. The obvious advantage with this approach is that web pages that were made with the older iPhone in mind will (almost always) work without any changes.

An important relative unit is em. This unit is based on the standard font size. (Which is usually 16px, CSS pixels, that is.)

Another important relative unit is % (percentage). An HTML element can have a width and height specified in a percentage of its parent element.

In general, using the relative units is preferred since it will adapt more readily to exotic screen sizes.

Rule of thumb

Some UI elements should not be proportionally resized. Whereas general layouts, list widths, etc, are well suited for CSS percentage units, there is a category of graphical element that is not: Buttons. Or to be precise, anything that requires the user to touch some area of the screen. It is appropriate to assign at least 7-10 mm minimum target area and 2 mm padding between elements. Infrequently used targets can be smaller and targets that trigger actions that are not easy to undo (such as deleting a document or sending a message) should be larger. 

Tablets are different

The larger screen real estate of tablets adds yet another dimension to consider. As an example, the image below shows a popular Android e-mail client. A larger screen could easily display the full message on the right-hand side of the screen, while keeping the list of messages to the left.

So, not only do we have to consider the display size, but also how that display size can enrich the user experience. 

How can we detect that we are using a tablet?

There is no future-proof, bullet-proof way to do this. But we may apply some heuristics. This code could be inserted right after the mosync.isWindowsPhone variable in wormhole.js. (This JavaScript file is included when you create a new MoSync HTML5 project).

mosync.getPixelDevicePixelRatio = function() {
  return window.devicePixelRatio === undefined ? 1 : window.devicePixelRatio;
};
mosync.getAndroidDips = function() {
  return window.screen.width / mosync.getPixelDevicePixelRatio();
}
mosync.isRetina = (mosync.isIOS && mosync.getPixelDevicePixelRatio() > 1);
// 641 dips is a good threshold for 'tablet' type Android devices, modify at will.
mosync.isLargeScreen = mosync.isRetina || (mosync.isAndroid && getAndroidDips() >= 641); 

Note: the above code only works for Android and iOS. 

Landscape to portrait, portrait to landscape

By default, MoSync does not support orientation changes. To make sure it works for all platforms, add these lines to the MyMoblet constructor of main.cpp in WormholeDemo just right after the call to extractFileSystem:

maScreenSetOrientation(SCREEN_ORIENTATION_DYNAMIC);
maScreenSetSupportedOrientations(MA_SCREEN_ORIENTATION_LANDSCAPE_LEFT |
  MA_SCREEN_ORIENTATION_LANDSCAPE_RIGHT | MA_SCREEN_ORIENTATION_PORTRAIT |
  MA_SCREEN_ORIENTATION_PORTRAIT_UPSIDE_DOWN);

Using device dependent style sheets

The MoSync Wormhole framework allows for determining the currently running platform. This can be used to dynamically load the proper style sheet. The WormholeDemo example does this in the initialization of the HTML5:

// Load different themes for different platforms.
if (mosync.isIOS) {
  loadjscssfile("js/themes/apple/theme.css", "css");
  // Fire up JQTouch.
  var jQT = $.jQTouch({
    statusBar : 'black',
  });
} else if ... // Other platforms

We may add other criteria such as whether it is an iPad, a hires (retina) display, or a tablet. Then we can use a special CSS file that is appropriate for that platform. Please note that It's perfectly ok to call loadjscssfile several times with different CSS files -- this makes it easier to share styles across several platforms.

Images, icons, and its ilk

It is preferrable not to auto-scale icons, logos or other images that have been designed with pixel boundaries in mind. This could result in blurry, low quality icons. (Pictures may be fine to scale automatically, though.)

Here is a list of all image sizes that you may need to provide and that MoSync supports. The size in parenthesis is how much of the image that may contain non-transparent pixels. (The image format is transparent PNG or all platforms.) 

PlatformType of imageImage Size (physical pixels)
iOSNavigator bar icon*20 x 20
iOS (hires)Navigator bar icon*40 x 40
iOSTab bar icon*30 x 30
iOS (hires)Tab bar icon*60 x 60
iOS (iPhone)Launcher icon57 x 57
iOS (iPhone, hires)Launcher icon114 x 114
iOS (iPad)Launcher icon72 x 72
Windows PhoneAction icon*48 x 48 (26 x 26)
Windows PhoneLauncher icon62 x 62
Windows PhoneWindows Phone Tile image137 x 137
Android (ldpi)Action icon*24 x 24 (22 x 22)
Android (mdpi)Action icon*32 x 32 (28 x 28)
Android (hdpi)Action icon*48 x 48 (42 x 42)
Android (xdpi)Action icon*64 x 64 (56 x 56)
Android (ldpi)Launcher icon36 x 36 (32 x 32)

* If you want the HTML5 app to be native looking.

For more information on assigning app icons, see ../../../../../sdk/tools/guides/ide/adding-application-icons/index.html.

How to responsively load images

To scale images to the proper size, you may either load the image and scale it to the proper size (using for example the above mentioned em/percentage units). But as previously mentioned, some images are not meant for just scaling them proportionally. Attached to this article is the JavaScript file mosponsive.js (for some unrelated reason renamed; please re-rename when downloading). This script handles HTML img tag rewriting. To use it, just include it in your index.html file right after wormhole.js.

How does it work? Let's show an example where we want one image for general android devices, one image for high density screens and one image for high density, android devices:

<img src="image0.png"
     data-android="image1.png"
     data-xhdpi="image2.png"
     data-android-xhdpi="image3.png"/>  

On startup, the script will rewrite the above tag and make sure that the proper image is used. The script handles all img attributes that starts with "data-" and then tries to match each criteria to the current device.

The script can handle three kinds of criteria: platform, screen density and screen size.

The platform is any one of android, ios or wp.

The screen density is how many pixels there are per inch (ppi): ldpi (~120 ppi), mdpi (~160 ppi), hdpi (~240 ppi) and xhdpi (~320 ppi).

The screen size is the width of the device, measured in device-independent pixels (dp). This roughly corresponds to the actual size of the device; one device independent pixel is ~1/160". (For more info, see for example http://en.wikipedia.org/wiki/Device_independent_pixel). The available screen sizes are small (>426 dp wide), medium (>470 dp wide), large (>720 dp wide) and xlarge (>960 dp wide) -- more or less following the Android standard but ignoring height. 

A few words about fonts

There are just a handful of native fonts for Android, Windows Phone have more and later versions of iOS even more (see iosfonts.com for a good overview) – but more importantly, they share no fonts. The at-rule @font-face can bridge this font gap. Android, iOS and Windows Phone all support TrueType fonts; add one to the project's LocalFiles directory and refer to it in the @font-face at-rule:

@font-face {
  font-family: crayon;
  src: url('DK_Crayon_Crumble.ttf');
}

Final words

Creating a cross-platform app requires a lot a effort. But by using relative units and selecting CSS styles dynamically, complexity can be brought down to a workable level. 

PS. Did we mention that you can create a fully native UI in MoSync just using HTML? Have a look here: ../../../../../sdk/js/examples/wormholenativeui/index.html. DS.

MoSync SDK 3.3
Copyright © 2013 MoSync AB
www.mosync.com