Introduction
Mobile application development has always had its own unique set of challenges. The effort to create a one-size-fits-all view is effectively doubled when you add orientation change on top of all the various device resolutions in existence. You can get a good idea of the variety at Screen Sizes. There you’ll see dozens of different different phones and tablets all with varying widths, heights and pixel densities.
Our job as developers is to create an app that provides a seamless experience on all of these devices. In part one of this post, we’ll explore a SASS/CSS approach that will help us achieve great results.
There are some general CSS rules of thumb that can help us achieve the desired results using the browser to layout the DOM for our apps. For example, we can use em or rem instead of px for sizing. We can also set our images to scale based on the size of the container they are in. Sencha Touch even has a number of tools to help us address device support. We can use Ext.app.Profile to create a custom experience for tablets, phones or any other device we choose. All of these things are helpful but don’t directly address the problem of orientation changes.
Handling orientation change is unique to mobile development and be challenging for quite a number of reasons. For example, a view designed for portrait might not look very good or even be useful when it’s stretched out to landscape and vice versa. So, how do we, as developers, provide a seamless experience when the user keeps rotating their device ?
Touch Layouts
The Sencha Touch HBox and VBox layouts can help with this to some extent. Behind the scenes, they use css flexbox to give you a way to position content horizontally or vertically and allow you to size your content as a percentage or as a fixed dimension. Like all of the other layouts, they are extremely easy to use and backwards compatible.
However, the HBox and VBox layouts are not without their downsides. They do add extra DOM elements to your markup and they don’t support all of the flexbox features. Some of those features are needed to properly address our orientation concerns.
Flexbox
For instance, flex-wrap can be used on the container to wrap content to additional lines on the cross-axis if the main axis doesn’t have enough space.
The order css property can be used on individual content items to change their layout order within the container.
A Note on Flexbox History
Flexbox has gone through a number of iterations since its debut in 2009 (“box”, “flex()”, “flexbox” and now “flex”). The current working draft as of this writing is March 2014. However, you may need to prefix your flexbox properties and possibly add the older “box” properties to your stylesheets depending on the devices and browsers you are targeting. Flexbox support If you’d like to learn more about flexbox, you can read more at Planning for Aliens.
Orientation
Now lets put a few things together to make an orientation aware component. Say, for instance, we have a simple input form that contains two distinct groups of input elements; Billing Address and Shipping Address.
Currently we are using the VBox layout to display these components on top of each other. This looks great in portrait. However, it results in a lot of wasted space when viewed in landscape. What we would really like is to display them stacked vertically in portrait mode and then displayed side by side in landscape. Lets look at the before and after code snippet for our view.
We need to get rid of the VBox layout and replace it with the default layout and then make better use of CSS to format our components as we need to. The first thing we do is strip out the layout and flex properties from out view. We are going to use the default layout instead. Lets also add a class to our view so that we have something to reference in our SASS.
// Layout children in a column with each component equally flexed
.orientation-container {
// Target x-inner div of the container. Set its display to flex and direction to column
> .x-inner {
display : flex;
flex-direction : column;
// The default for align-items is “stretch” which sizes the items to fill the cross axis
align-items : strech;
// Select the child containers and set their flex each to 1
> .x-container {
flex : 1;
border : 1px solid #666;
background-color : #fff;
}
}
}
// Layout divs in a row when the device is in landscape
@media screen and (orientation:landscape) {
.orientation-container {
> .x-inner {
flex-direction : row;
}
}
}
In our SASS file we target the x-inner div of the container and set display: flex and set the flex-direction to column (which is actually the default value). We’ll also size the items to fill the cross axis by setting the align-items property to stretch. Let’s give the child components > div each a flex of 1 which will work well for our simple example here. You can easily make one of your child components bigger than the other by using different CSS selectors and assigning them their own flex values and/or widths. Finally, we’ll use a media query to change the flex-direction when the orientation changes to landscape.
Here’s what it looks like in portrait and landscape mode.
Results
Now, if you rotate your device, your view changes from portrait to landscape and your child components stack either vertically or horizontally. We now have a simple orientation aware container that changes its layout when the device is rotated. You can even add that “orientation-container” class to any container that needs support. If you need to change the order of the children or need wrapping, then you can add that too. Taking control of the layout in CSS not only gives you more options and a lighter DOM but more “flexibility”. You can check out the code here – Sencha Fiddle.
In the next part of this series, Brice Mason will discuss the options we have when our requirements get more complicated and simple CSS is not enough.
Timothy Eagan
Related Posts
-
Orientation Aware Apps in Sencha Touch Part 2 of 2
In part one of this series, Tim Eagan introduced us to the challenge of developing…
-
Sencha Touch 2 Touch Events Re-firing
While generally we try to avoid native browser alert() and confirm() we sometimes have no…