Share via


Quickstart: Defining app layouts (HTML)

[This article is for Windows 8.x and Windows Phone 8.x developers writing Windows Runtime apps. If you’re developing for Windows 10, see the latest documentation]

You can define app layouts for any window size or orientation.

See this feature in action as part of our App features, start to finish series: Windows Store app UI, start to finish

Objective: After reading this article you will have a solid understanding of how to use HTML, Cascading Style Sheets (CSS), and JavaScript to create a fluid UI that looks good and functions well in all view states.

Prerequisites

  • Have a design in mind for your app.

    You can learn about planning and designing a Windows Runtime app in Defining vision.

  • Be familiar with resizable windows in Windows 8.1.

    You can learn more about view states in UX guidelines for layout and scaling.

  • Understand CSS media queries.

    Media queries are defined in the World Wide Web Consortium (W3C) Media Queries specification. You can see media queries in action in our CSS media queries sample.

  • Know how to use the Cascading Style Sheets, Level 3 (CSS3) advanced layout features, especially CSS3 Grid Alignment.

    You can learn about CSS3 advanced layout features and Grid Alignment in CSS.

The Adaptive layout with CSS sample

This article illustrates the basic concepts involved in defining app layouts by describing how layouts are implemented in the Adaptive layout with CSS sample. This sample is a simulated weather app that displays the current day's weather and the ten-day forecast. It demonstrates how to use CSS and HTML, the CSS grid, the ListView control, and CSS media queries to create a fluid app layout.

Before we get into the details, let's take a look at the structure of the Adaptive layout with CSS sample. The app consists of three HTML pages. The first is a top-level page called App.html that defines the main surface for the app's UI items. It includes a back button, a title and subtitle, an app menu, the app bar buttons, and an area for displaying content (the white area in the following image).

The sample app's main page

The other two HTML pages, Current.html and TenDay.html, define the structure of the content that is displayed in the content area of the main page. The Current.html page displays details about the current day's weather:

The current weather page

The TenDay.html page displays details about the ten-day forecast:

The ten-day forecast page

We'll focus on the parts of the Adaptive layout with CSS sample that define the layout of the app's main page, and the layout of the ten-day forecast.

Here's what app's main page looks like when displaying the ten-day forecast on a 10.6" display at 1366 x 768 resolution in full-screen portrait and landscape orientations, as well as placed side by side with another app, resized to a narrow layout and a wider layout.

portrait, landscape, narrow, and wide layouts

Ensure that the app fills the available screen area

A well-designed app has a UI surface that takes up all of the available screen area. At first this may seem like a difficult challenge given the wide range of device form factors, resolutions, and orientations that an app needs to accommodate. Fortunately, CSS makes it easy.

To ensure that the app takes up all the available screen area:

  1. Use a div element as the top-level container for all other UI elements on the page.

    <body>
        <div class="win-ui-dark appGrid">
            <!-- TODO: Define page structure here. -->
        </div>
    </body>
    
  2. Use the CSS properties, vw and vh, to set the width and height properties of the div relative to the viewport. For example, use 100vw (viewport width) and 100vh (viewport height) to fill the viewport, as shown here.

    .appGrid {
        width: 100vw;
        height: 100vh;
        /* TODO: Add other styles here. */
    }
    

    vw and vh can be specified for any element, no matter how deep within the hierarchy. Because the sizing context for the viewport doesn't change, there is no need to account for inherited sizing.

    Note  The sample sets the width and height properties to 100%.

     

Define the basic layout of the main page

When you lay out your app UI, it's best to start with the landscape orientation. After you define your landscape layout, it's easy to adapt it for portrait and for narrow width layouts.

Use HTML to define the UI items for the page

An app UI typically contains items such as navigation buttons, headings, menus, controls, and so on. Add these UI items as child HTML elements of the top-level div element for the page.

The following HTML defines the UI items for the Adaptive layout with CSS sample app's top-level page. The items include the back button, title and subtitle, app menu, the main content area, and the app bar buttons.

<body>
    <div class="win-ui-dark appGrid">
        <header aria-label="Header content" role="banner">
            <button class="win-backbutton" aria-label="Back"></button>
            <h1 class="titlearea win-type-ellipsis">
                <span class="win-type-xx-large titlecontainer" tabindex="0"><span class="pagetitle">Mountains</span><span class="win-type-x-large chevron">&#xE099</span></span>
                <span class="win-type-x-large pagesubtitle">Rainer</span>
            </h1>
        </header>
        <div id="headerFlyout" data-win-control="WinJS.UI.Menu">
            <button data-win-control="WinJS.UI.MenuCommand" data-win-options="{id:'rainierMenuItem', label:'Rainier'}"></button>
            <button data-win-control="WinJS.UI.MenuCommand" data-win-options="{id:'stHelensMenuItem', label:'St. Helens'}"></button>
            <button data-win-control="WinJS.UI.MenuCommand" data-win-options="{id:'olympusMenuItem', label:'Olympus'}"></button>
            <button data-win-control="WinJS.UI.MenuCommand" data-win-options="{id:'bakerMenuItem', label:'Baker'}"></button>
            <button data-win-control="WinJS.UI.MenuCommand" data-win-options="{id:'adamsMenuItem', label:'Adams'}"></button>
        </div>
        <div class="appViewContentMask">
            <div class="appViewContent">
                <div id="current-page" class="page" data-win-control="WinJS.UI.HtmlControl" data-win-options="{uri: '/html/current.html', data: FluidAppLayout.Data.mountains[0].weatherData[0]}"></div>
                <div id="ten-day-page" class="page" data-win-control="WinJS.UI.HtmlControl" data-win-options="{uri: '/html/tenDay.html', data: FluidAppLayout.Data.mountains[0].weatherData}"></div>
            </div>
        </div>
    </div>
    <div id="appbar" class="win-ui-dark appbar" data-win-control="WinJS.UI.AppBar">
        <button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id: 'current', label: 'Current', icon: 'calendarday', type: 'toggle', onclick: FluidAppLayout.transitionPivot, selected: 'false', tooltip: 'Get the current report'}"></button>
        <button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id: 'tenDay', label: 'Ten day', icon: 'calendarweek', type: 'toggle', onclick: FluidAppLayout.transitionPivot, selected: 'false', tooltip: 'Get the ten day report'}"></button>
    </div>
</body>

Use CSS grids to position UI items on the HTML page

One of the best ways to achieve a fluid and adaptable UI layout is by using CSS grids. That's because the grid can automatically expand to fill the space that it's given, and it exposes a rich set of properties that make it easy to tailor the UI layout for different window sizes. Because the position of elements in a grid is independent of the order in which they are specified—that is, their position is dictated purely by CSS rather than by their order in HTML markup—it's easy to give elements different arrangements on different screen sizes or in different orientations, or even to avoid displaying some elements entirely in some layouts.

Laying out the main page

  1. The Adaptive layout with CSS sample app applies a CSS grid to the top-level div on the App.html page by setting the display property of the div -ms-grid. This top-level grid defines the overall structure for positioning UI items on the app's main page.

  2. Next, the sample app defines the columns and rows of the grid by setting the value of the -ms-grid-columns and -ms-grid-rows properties.

    The following CSS code applies a grid to the top-level div on the sample's main page. This grid is used to position the items that make up the app's header (the back button, title and subtitle, and app menu), and to set the position of the main content area.

    .appGrid {
        display: -ms-grid;
        -ms-grid-columns: 120px 1fr;
        -ms-grid-rows: 120px 1fr; 
    
        /* Other properties omitted for clarity. */
    
    }
    

    The preceding CSS code creates a grid with two columns and two rows. The first column is 120 pixels wide, and the second column is one "fractional unit" wide. That means the column width automatically expands to fill the available space that is not taken up by the first column. The rows are defined in a similar manner.

    This illustration shows how the grid divides the app's main page:

    The main page grid

  3. Next, the Adaptive layout with CSS sample sets the position of UI items by assigning each item to a particular cell in the grid. To do that, the sample applies the -ms-grid-column and -ms-grid-row properties to elements on the page. The CSS grid supports several other properties for positioning items relative to the cell boundaries, and allowing items to span multiple columns or rows. To learn more, see Grid layout.

    The following CSS code positions the header element of the sample app's main page in column 1, row 1 of the top-level grid, and allows the element to span both columns of the grid. The code also creates a "child" grid within column 1, row 1 of the top-level grid. The child grid is used to position the individual items that make up the header (the back button, title and subtitle, and app menu).

    header[role=banner] {
        -ms-grid-column: 1;
        -ms-grid-row: 1;
        -ms-grid-column-span: 2;
    
        /* Child grid for positioning header items.*/
        display: -ms-grid;
        -ms-grid-columns: 120px 1fr;
        -ms-grid-rows: 1fr;
    }
    

    The preceding code creates a grid in the area highlighted in blue in the following image.

    The child grid for the sample app's header

    The Adaptive layout with CSS sample uses nested div elements to define the main content area where the current forecast and the ten-day forecast appears:

    <div class="appViewContentMask">
        <div class="appViewContent">
            <div id="current-page" class="page" data-win-control="WinJS.UI.HtmlControl" data-win-options="{uri: '/html/current.html', data: FluidAppLayout.Data.mountains[0].weatherData[0]}"></div>
            <div id="ten-day-page" class="page" data-win-control="WinJS.UI.HtmlControl" data-win-options="{uri: '/html/tenDay.html', data: FluidAppLayout.Data.mountains[0].weatherData}"></div>
        </div>
    </div>
    

    Notice in the preceding example that the Windows Library for JavaScript HtmlControl control is used to dynamically include the HTML pages for the current and ten-day forecasts. To learn more about WinJS controls, see Quickstart: Adding WinJS controls and styles.

    The following CSS code positions the appViewContentMask div in column 2, row 2 of the top-level grid. It also sets properties to ensure that the content fills the entire grid cell, that any content that doesn't fit in the cell is hidden.

    .appViewContentMask {
        -ms-grid-column: 2;
        -ms-grid-row: 2;
        width: 100%;
        height: 100%;
        overflow: hidden;
    
        /* Other properties omitted for clarity. */
    
    }
    

    The following CSS code turns the appViewContent div into a child grid containing a single cell that fills the area defined by the appViewContentMask div. Using a child grid makes it easy to reflow the content when the view state changes the size or orientation of the app.

    
    .appViewContent {
        width: 100%;
        height: 100%;
        display: -ms-grid;
        -ms-grid-columns: 1fr;
        -ms-grid-rows: 1fr;
    }
    

    The CSS code assigns the grid for the content area to the area highlighted in blue:

    The grid in the sample app's content area

Define the basic layout of the ten-day forecast

The ten-day forecast is a collection of items that are managed and displayed by using a WinJS ListView control. Each item consists of an image and a set of strings, including the date, high and low temperatures, "feels like" temperature, and chance of snow:

Layout of items in the ten-day forecast

The following HTML page defines the UI for the items in the ten-day forecast. The Adaptive layout with CSS sample uses WinJS templates and data binding to supply data to the ListView control. This topic focuses on laying out your UI, so we won't get into templates and data binding here. If you want to learn more about templates and data binding, see How to use templates to bind data.

<body>
    <div class="tenDayPage">
        <div id="tenDayTemplate" class="tenDayTemplate" data-win-control="WinJS.Binding.Template">
            <div class="tenDayGrid">
                <div class="win-type-x-large tenDayDate" data-win-bind="innerHTML: date">
                </div>
                <div class="tenDayImg">
                    <img data-win-bind="src: imgSrc" />
                </div>
                <div class="win-type-x-large tenDayHighLow">
                    <span class="tenDayHigh" data-win-bind="innerHTML: hi"></span>
                    <span>/</span>  
                    <span class="tenDayLow" data-win-bind="innerHTML: low"></span>
                </div>
                <div class="tenDayFeelsLike">
                    <span>Feels like </span>
                    <span data-win-bind="innerHTML: feelsLike"></span>
                </div>
                <div class="tenDayChanceOfSnow">
                    <span>Chance of snow is </span>
                    <span data-win-bind="innerHTML: chanceOfSnow"></span>
                </div>
            </div>
        </div>
        <div id="tenDayListView" class="tenDayListView" data-win-control="WinJS.UI.ListView" data-win-options="{layout: {type: WinJS.UI.GridLayout}}"></div>
    </div>
</body>

Notice that the previous example uses special WinJS CSS classes for typography to set an extra large font size for the date and high/low temperatures strings. That's what class="win-type-x-large" means in the tenDayDate and tenDayHighLow div elements.

The sample app uses the following CSS code to ensure that the TenDay.html page and its ListView control fills the parent container (the content area of the app's main page).

/* Size Page to full size of parent container */
.tenDayPage
{
    height: 100%;
}

/* List View Control */
.tenDayListView
{
    width: 100%;
    height: 100%;
}

Use CSS media queries to apply view-specific layouts and styles

By using CSS media queries, you can easily define different styles to apply to the HTML items in your app depending on the window size. You can use a separate media query for each different layout, or you can combine media queries to apply the same set of styles to multiple layouts. Here we describe the media queries that the Adaptive layout with CSS sample uses to lay out its main page and the items in the ten-day forecast.

Laying out the main page for a narrow layout

If you use the sample app, you'll notice that the size and layout of UI items don't change much between portrait, landscape, and resized layouts that are wide. When the app is resized to a width that is less than 500 pixels, however, you see the following changes:

  • The UI items in the app header get smaller.
  • The layout changes from two columns and two rows, to a single-column where the header occupies the first row, and the main content area occupies the second row.

Header layout differences between narrow and wide layouts

These changes are applied through a CSS media query that defines a different set of styles specifically for narrow widths:

@media (max-width:499px) {
    .appGrid {
        display: -ms-grid;
        -ms-grid-columns: 1fr;
        -ms-grid-rows: 120px 1fr;
        width: 100%;
        height: 100%;
    }

    header[role=banner] {
        -ms-grid-column: 1;
        -ms-grid-row: 1;
        -ms-grid-columns: 60px 1fr;
        -ms-grid-rows: 1fr;
        display: -ms-grid;
    }

        header[role=banner] .win-backbutton {
            -ms-grid-column: 1;
            -ms-grid-row: 1;
            margin-left: 20px;
            margin-top: 75px;
        }

        header[role=banner] .titlearea {
            -ms-grid-column: 2;
            -ms-grid-row: 1;
            margin-top: 69px;
            max-width: 260px;
        }

    .appViewContentMask {
        -ms-grid-column: 1;
        -ms-grid-row: 2;
    }

In the preceding CSS code, a new value for the –ms-grid-columns property changes the app's main grid (appGrid) from two columns to one. The CSS code also defines a new child grid for the items in the app's header, and positions the header items in the new grid. Finally, the code moves the content area (appViewContentMask) from column 2, row 2 of the old grid, to column 1, row 2 of the new grid.

Laying out the ten-day forecast for a narrow layout

You'll notice changes in the layout of the individual items in the ten-day forecast when you resize the app to a width less than 500 pixels. When the width is greater than 500 pixels, the items are laid out vertically using a single-column grid. When the width is less than 500 pixels, the items switch to a horizontal orientation using a two-column grid.

The following image shows what an items in the ten-day forecast looks like in the different layouts.

Item layout differences between narrow and wide layouts

To achieve the different layouts, the sample uses CSS media queries to apply styles based on the current view state. The sample defines one set of styles that are common across all view states, and another set just for the layouts when the width is less than 500px:

/* Styles that are common across all view states */
    .tenDayGrid
    {
        width: 190px;
        height: 250px;
        overflow: hidden;
        padding: 10px;
        display: -ms-grid;
        -ms-grid-columns: 1fr;
        -ms-grid-rows: (auto)[5];
    }

    .tenDayDate
    {
        -ms-grid-column: 1;
        -ms-grid-row: 1;
    }

    .tenDayImg
    {
        -ms-grid-column: 1;
        -ms-grid-row: 2;
    }

    .tenDayHighLow
    {
        -ms-grid-column: 1;
        -ms-grid-row: 3;
    }

    .tenDayFeelsLike
    {
        -ms-grid-column: 1;
        -ms-grid-row: 4;
    }
    .tenDayChanceOfSnow
    {
        -ms-grid-column: 1;
        -ms-grid-row: 5;
    }
}

/* Define the template for the width less than 500px */
@media (max-width:499px)
{
    .tenDayDate
    {
        font-weight: 600;
    }

    .tenDayDate > .day
    {
       font-weight: 200;
    }

    .tenDayHighLow
    {
        font-weight: 300;
    }

    .tenDayFeelsLike, .tenDayChanceOfSnow
    {
        font-weight: 300;
    }

    .tenDayGrid
    {
        width: 250px;
        height: 150px;
        overflow: hidden;
        padding: 10px;
        display: -ms-grid;
        -ms-grid-columns: auto 1fr;
        -ms-grid-rows: (auto)[4];
    }

    .tenDayDate
    {
        -ms-grid-column: 1;
        -ms-grid-row: 1;
        -ms-grid-column-span: 2;
    }

    .tenDayImg
    {
        -ms-grid-column: 1;
        -ms-grid-row: 2;
        -ms-grid-row-span: 3;
    }

    .tenDayHighLow
    {
        -ms-grid-column: 2;
        -ms-grid-row: 2;
    }

    .tenDayFeelsLike
    {
        -ms-grid-column: 2;
        -ms-grid-row: 3;
    }
    .tenDayChanceOfSnow
    {
        -ms-grid-column: 2;
        -ms-grid-row: 4;
    }
}

Use JavaScript to process window resize events, if necessary

It's best to define as much of your app's layout as possible by using CSS and media queries. However, sometimes you'll need to use JavaScript to handle layout issues that CSS can't address.

For example, the sample app uses a WinJS ListView control to display the items in the ten-day forecast, and switches the ListView between list and grid mode depending on the app width. When the sample app is 500 pixels or wider, the ListView uses grid mode to flow items vertically and horizontally to fill the parent container. When the app is less than 500 pixels, the ListView uses list mode to arrange items in a vertical list.

To create view-specific layouts in JavaScript, register an event listener for the window resize event. In the event listener code, query the clientWidth property and configure the layout accordingly.

In the following example, the Adaptive layout with CSS sample sets the ListView to grid mode. If the window width is less than 500 pixels, the ListView changes to list mode. The app's event listener listens for the resize event and then queries the clientWidth property and changes the ListView accordingly.

function ready(element, options) { 
        element.winControl = this; 
        var that = this; 
        WinJS.UI.process(element).done(function () { 
            that.listView = element.querySelector(".tenDayListView").winControl; 
            var itemTemplate = element.querySelector(".tenDayTemplate"); 
            var listViewLayout = new WinJS.UI.GridLayout(); 
 
            if (document.body.clientWidth <= 499) { 
                listViewLayout = new WinJS.UI.ListLayout(); 
            } 
            else { 
                element.style.opacity = "0"; 
            } 
 
            // ... 
 
            window.addEventListener("resize", tenDayResize, false); 
        }); 
    } 
 
    function tenDayResize(e) { 
 
        var listview = document.querySelector(".tenDayListView").winControl; 
 
        if (document.body.clientWidth <= 499) { 
            if (!(listview.layout instanceof WinJS.UI.ListLayout)) { 
                listview.layout = new WinJS.UI.ListLayout(); 
            } 
        } 
        else { 
            if (listview.layout instanceof WinJS.UI.ListLayout) { 
                listview.layout = new WinJS.UI.GridLayout(); 
            } 
        } 
    } 

Summary

You should now understand how to use HTML, CSS, and JavaScript to create a fluid UI for your app that looks good and functions well in all window sizes.

Adaptive layout with CSS sample

CSS media queries sample

Hands-on labs for Windows 8

Developing reader apps

Media Queries specification

ListView control

Internet Explorer 10 Guide for Developers