Metro: Understanding CSS Media Queries

If you are building a Metro style application then your application needs to look great when used on a wide variety of devices. Your application needs to work on tiny little phones, slates, desktop monitors, and the super high resolution displays of the future.

Your application also must support portable devices used with different orientations. If someone tilts their phone from portrait to landscape mode then your application must still be usable.

Finally, your Metro style application must look great in different states. For example, your Metro application can be in a “snapped state” when it is shrunk so it can share screen real estate with another application.

In this blog post, you learn how to use Cascading Style Sheet media queries to support different devices, different device orientations, and different application states. First, you are provided with an overview of the W3C Media Query recommendation and you learn how to detect standard media features.

Next, you learn about the Microsoft extensions to media queries which are supported in Metro style applications. For example, you learn how to use the –ms-view-state feature to detect whether an application is in a “snapped state” or “fill state”.

Finally, you learn how to programmatically detect the features of a device and the state of an application. You learn how to use the msMatchMedia() method to execute a media query with JavaScript.

Using CSS Media Queries

Media queries enable you to apply different styles depending on the features of a device. Media queries are not only supported by Metro style applications, most modern web browsers now support media queries including Google Chrome 4+, Mozilla Firefox 3.5+, Apple Safari 4+, and Microsoft Internet Explorer 9+.

Loading Different Style Sheets with Media Queries

Imagine, for example, that you want to display different content depending on the horizontal resolution of a device. In that case, you can load different style sheets optimized for different sized devices.

Consider the following HTML page:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>U.S. Robotics and Mechanical Men</title>

    <link href="main.css" rel="stylesheet" type="text/css" />

    <!-- Less than 1100px -->
    <link href="medium.css" rel="stylesheet" type="text/css"
        media="(max-width:1100px)" />

    <!-- Less than 800px -->
    <link href="small.css" rel="stylesheet" type="text/css"
         media="(max-width:800px)" />

</head>
<body>
    <div id="header">
        <h1>U.S. Robotics and Mechanical Men</h1>
    </div>

    <!-- Advertisement Column -->
    <div id="leftColumn">
        <img src="advertisement1.gif" alt="advertisement" />
        <img src="advertisement2.jpg" alt="advertisement" />
    </div>

    <!-- Product Search Form -->
    <div id="mainContentColumn">
        <label>Search Products</label>
        <input id="search" /><button>Search</button>
    </div>

    <!-- Deal of the Day Column -->
    <div id="rightColumn">
        <h1>Deal of the Day!</h1>
        <p>
            Buy two cameras and get a third camera for free! Offer
            is good for today only.
        </p>
    </div>

</body>
</html>

The HTML page above contains three columns: a leftColumn, mainContentColumn, and rightColumn. When the page is displayed on a low resolution device, such as a phone, only the mainContentColumn appears:

clip_image001

When the page is displayed in a medium resolution device, such as a slate, both the leftColumn and the mainContentColumns are displayed:

clip_image002

Finally, when the page is displayed in a high-resolution device, such as a computer monitor, all three columns are displayed:

clip_image003

Different content is displayed with the help of media queries. The page above contains three style sheet links. Two of the style links include a media attribute:

<link href="main.css" rel="stylesheet" type="text/css" />

<!-- Less than 1100px -->
<link href="medium.css" rel="stylesheet" type="text/css"
    media="(max-width:1100px)" />

<!-- Less than 800px -->
<link href="small.css" rel="stylesheet" type="text/css"
     media="(max-width:800px)" />

The main.css style sheet contains default styles for the elements in the page.

The medium.css style sheet is applied when the page width is less than 1100px. This style sheet hides the rightColumn and changes the page background color to lime:

html {

   background-color: lime;

}

#rightColumn {

   display:none;

}


Finally, the small.css style sheet is loaded when the page width is less than 800px. This style sheet hides the leftColumn and changes the page background color to red:

html {

   background-color: red;

}

#leftColumn {

   display:none;

}


The different style sheets are applied as you stretch and contract your browser window. You don’t need to refresh the page after changing the size of the page for a media query to be applied:

clip_image004

Using the @media Rule

You don’t need to divide your styles into separate files to take advantage of media queries. You can group styles by using the @media rule.

For example, the following HTML page contains one set of styles which are applied when a device’s orientation is portrait and another set of styles when a device’s orientation is landscape:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Application1</title>

    <style type="text/css">

        html {
            font-family:'Segoe UI Semilight';
            font-size: xx-large;
        }


        @media screen and (orientation:landscape) {
            html {
                background-color: lime;
            }

            p.content {
                width: 50%;
                margin: auto;
            }
        }

        @media screen and (orientation:portrait) {
            html {
                background-color: red;
            }

            p.content {
                width: 90%;
                margin: auto;
            }
        }

    </style>

</head>
<body>

<p class="content">
    Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
    Maecenas porttitor congue massa. Fusce posuere, magna sed
    pulvinar ultricies, purus lectus malesuada libero, sit
    amet commodo magna eros quis urna.
</p>

</body>
</html>

When a device has a landscape orientation then the background color is set to the color lime and the text only takes up 50% of the available horizontal space:

clip_image006

When the device has a portrait orientation then the background color is red and the text takes up 90% of the available horizontal space:

clip_image007

Using Standard CSS Media Features

The official list of standard media features is contained in the W3C CSS Media Query recommendation located here:

http://www.w3.org/TR/css3-mediaqueries/

Here is the official list of the 13 media features described in the standard:

· width – The current width of the viewport

· height – The current height of the viewport

· device-width – The width of the device

· device-height – The height of the device

· orientation – The value portrait or landscape

· aspect-ratio – The ratio of width to height

· device-aspect-ratio – The ratio of device width to device height

· color – The number of bits per color supported by the device

· color-index – The number of colors in the color lookup table of the device

· monochrome – The number of bits in the monochrome frame buffer

· resolution – The density of the pixels supported by the device

· scan – The values progressive or interlace (used for TVs)

· grid – The values 0 or 1 which indicate whether the device supports a grid or a bitmap

Many of the media features in the list above support the min- and max- prefix. For example, you can test for the min-width using a query like this:

(min-width:800px)

You can use the logical and operator with media queries when you need to check whether a device supports more than one feature. For example, the following query returns true only when the width of the device is between 800 and 1,200 pixels:

(min-width:800px) and (max-width:1200px)

Finally, you can use the different media types – all, braille, embossed, handheld, print, projection, screen, speech, tty, tv — with a media query. For example, the following media query only applies to a page when a page is being printed in color:

print and (color)

If you don’t specify a media type then media type all is assumed.

Using Metro Style Media Features

Microsoft has extended the standard list of media features which you can include in a media query with two custom media features:

· -ms-high-contrast – The values any, black-white, white-black

· -ms-view-state – The values full-screen, fill, snapped, device-portrait

You can take advantage of the –ms-high-contrast media feature to make your web application more accessible to individuals with disabilities. In high contrast mode, you should make your application easier to use for individuals with vision disabilities.

The –ms-view-state media feature enables you to detect the state of an application. For example, when an application is snapped, the application only occupies part of the available screen real estate. The snapped application appears on the left or right side of the screen and the rest of the screen real estate is dominated by the fill application (Metro style applications can only be snapped on devices with a horizontal resolution of greater than 1,366 pixels).

Here is a page which contains style rules for an application in both a snap and fill application state:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>MyWinWebApp</title>

    <style type="text/css">

        html {
            font-family:'Segoe UI Semilight';
            font-size: xx-large;
        }


        @media screen and (-ms-view-state:snapped) {
            html {
                background-color: lime;
            }
        }

        @media screen and (-ms-view-state:fill) {
            html {
                background-color: red;
            }
        }

    </style>

</head>
<body>

<p class="content">
    Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
    Maecenas porttitor congue massa. Fusce posuere, magna sed
    pulvinar ultricies, purus lectus malesuada libero, sit
    amet commodo magna eros quis urna.
</p>

</body>
</html>

When the application is snapped, the application appears with a lime background color:

clip_image009

When the application state is fill then the background color changes to red:

clip_image011

When the application takes up the entire screen real estate – it is not in snapped or fill state – then no special style rules apply and the application appears with a white background color.

Querying Media Features with JavaScript

You can perform media queries using JavaScript by taking advantage of the window.msMatchMedia() method. This method returns a MSMediaQueryList which has a matches method that represents success or failure.

For example, the following code checks whether the current device is in portrait mode:

if (window.msMatchMedia("(orientation:portrait)").matches) {
    console.log("portrait");
} else {
    console.log("landscape");
}

If the matches property returns true, then the device is in portrait mode and the message “portrait” is written to the Visual Studio JavaScript Console window. Otherwise, the message “landscape” is written to the JavaScript Console window.

You can create an event listener which triggers code whenever the results of a media query changes. For example, the following code writes a message to the JavaScript Console whenever the current device is switched into or out of Portrait mode:

window.msMatchMedia("(orientation:portrait)").addListener(function (mql) {
    if (mql.matches) {
        console.log("Switched to portrait");
    }
});

Be aware that the event listener is triggered whenever the result of the media query changes. So the event listener is triggered both when you switch from landscape to portrait and when you switch from portrait to landscape. For this reason, you need to verify that the matches property has the value true before writing the message.

Summary

The goal of this blog entry was to explain how CSS media queries work in the context of a Metro style application written with JavaScript. First, you were provided with an overview of the W3C CSS Media Query recommendation. You learned about the standard media features which you can query such as width and orientation.

Next, we focused on the Microsoft extensions to media queries. You learned how to use –ms-view-state to detect whether a Metro style application is in “snapped” or “fill” state. You also learned how to use the msMatchMedia() method to perform a media query from JavaScript.

Discussion

  1. Michael says:

    You said, “Your application needs to work on tiny little phones…” Can we take this as an unofficial indication that there is some possibility that Windows Phone 8 could support javascript/html5 application types, like we have for Win8 metro apps? :) If you say yes, I don’t think it would surprise anyone. I keep hoping that becomes a reality for WP8.