The Good & Bad of Level 4 Media Queries

This article discusses a bleeding edge browser feature in a state of flux, with pretty much non-existent browser support — beware!

CSS3 introduced media queries: the ability to make styling decisions based on features of the media a web page is being served on. The most popular of these were width and device-width, letting designers and developers use different layouts for different ranges of viewport and device sizes; for example changing from 2 columns down to 1 for narrower screens. The responsive design movement was born.

I'm quite opinionated about how width / device-width (in particular) should be used, but I'm going to refrain from going into that now. Maybe another time.

What's fresh?

Last year the W3C started work on the next iteration of media queries: Media Queries Level 4. It's a really early spec, but the WebKit team has already started to implement it.

The current editor's draft adds 4 new media features which can be queried:

  • script
  • luminosity
  • pointer
  • hover

I'm not too fussed about script. It's just true if JS is available or false if it isn't. I usually use a no-js / js class on the <html> element (à la HTML5 Boilerplate), so it just means this:

.js .thing {
    /* Apply JS-only styles */
}

would change to this:

@media (script) {
    .thing {
        /* Apply JS-only styles */
    }
}

and we'd save a few bytes of JS code. Yeah it's nice having a standard way of doing it, but it's not really worth it until every browser supports it, because we'd have to provide a fallback until then anyway.

luminosity could be fun... it describes the amount of ambient light as dim, normal or washed... most creative uses for that on the back of a postcard please.

But it's the last two which generate the most intrigue.

pointer can be coarse, fine or none, to describe the accuracy of the pointing device in use (mouse, touch, stylus, etc). So a touchscreen device would report coarse, a device with a mouse or stylus would report fine and a device with none of these (e.g. keyboard only) would report none.

Meanwhile, hover is true if the pointing device can relay a hover state (like a mouse can), or false if it can't (as is the case with touchscreens).

What's more, like other media queries, they're dynamic — plug in / unplug an input device and your styles will update accordingly.

This all sounds awesome.

At the moment, most developers seem to rely on an assumption that device size correlates to input type, so use their lovely device-width media queries to give narrow screens a touch-friendly interface and wide screens a mouse-friendly interface. This is of course complete rubbish because you can get tablets the size of a house nowadays and there are still plenty of mobile devices with HTML browsers which don't have touchscreens.

So surely we can stop assuming, and just ask the browser now, right?

Well, it depends. It all gets a bit fuzzy.

Multiplicity

The media query spec takes into consideration another point that a lot of web designers miss: a user can have multiple pointer devices connected simultaneously. The obvious examples are things like many of the new Windows 8 desktops, Microsoft Surface, or the Chromebook Pixel — all of which can have a touchscreen and will frequently be used with a mouse/trackpad. But there are also smartphone and tablet users who connect mice and pointer sticks for various reasons, including accessibility; and so on.

The spec handles this by reporting the features of the least capable pointer device. Let's see what happens with the mouse + touchscreen example:

Mouse? Touch? hover pointer
no no 0 none
yes yes 0 coarse
yes no 1 fine
no yes 0 coarse

Notice that if a touch input is present, media queries will report the same (pointer:coarse and hover:0), regardless of whether you've got a mouse connected.

A touch-optimised interface is typically more accessible and rarely a big inconvenience to a mouse user, so erring towards touch-friendly when in doubt makes sense. But is that always what we want?

Let's take a few use cases:

  1. I visit a site on my smartphone/tablet. The guy who wrote it kindly used a pointer:coarse media query with a load of rules to give me nice big pressable buttons, etc... good news!
  2. I visit a site on my "vintage" non-touch desktop. The guy who wrote it used a pointer:fine media query to ensure I get a really precise interface with loads of stuff on one screen... good news!
  3. I then get a new monitor for said desktop, which happens to support touch. The lovely interface I'm used to on my favourite web app then turns into a load of chunky boxes, and what's more he decided that everything should scroll sideways... bad news!

Obviously there's still an onus on us not to make touch interfaces which are unfriendly to mouse users here.

In browsers which don't support these media queries, we have to fall back to a safe, accessible-to-all layout — which again means touch-friendly, without relying on hover (we should probably all be doing this today, by the way). And by the time this spec is supported by all major browsers, even more devices are going to have a touchscreen. You will of course still be able to identify dinosaurs with mouse-but-no-touch devices and keyboard-only users, so you can tailor your interface for my Mum and sysadmins (never thought those two would go in the same category)... but the vast majority of people are going to see a touch interface, meaning few will get the niceness of a UI tailored for accurate pointing devices.

These media queries are starting to look a little bit redundant already.

I love the idea of a user with something like a Microsoft Surface doing some serious work at their desk with a keyboard and mouse, then detaching peripherals to head out the door with it as a tablet... and the interface automatically switching to a touch-friendly variant; then back again when they return and plug in again. But the least capable rule means the user will never see the mouse-optimised 'serious work' layout.

The "primary pointer" affair

There's an extra component to this: the spec includes the following phrase:

If a device has multiple input mechanisms, it is recommended that the UA reports the characteristics of the least capable pointing device of the primary input mechanisms.

This wording implies (and discussions on the W3C mailing list confirm) that not all connected pointing devices need be taken into account when determining the least capable. It's up to the operating system and browser between them to decide which count as primary input mechanisms.

This could be both good and bad.

On the plus side, if the browser and OS get it right, cases like my running-out-the-door-with-your-tablet example above could be a reality; relegating the touchscreen to a secondary input when a mouse and type cover (keyboard) are attached would achieve this.

But if they get it wrong, things could be much worse. What if you have a touchscreen device which also supports a stylus and the stylus is considered the only primary input, but you want to use touch? Media query rules for pointer:fine would be observed and you're left trying to poke fiddly buttons with your little finger.

Indeed, the WebKit implementation (here's a C++ diff for the proper nerds) currently only covers touch device detection and isn't dynamic yet, but will be eventually. There's a single isDeviceTouchScreen flag which, when set, will force the value of the pointer media feature to coarse and hover to 0, regardless of any other settings. It's up to the port (e.g. Safari, Chrome, ...) to set this flag, based on their knowledge of the system and choice of primary pointing devices; so there's even the potential for two different WebKit browsers on the same system to invoke different sets of styles if they choose differently.

So essentially it's in the browser and device vendors' hands. That doesn't make me feel very comfortable as a developer — I don't want to have to reply to questions from users with "sorry, your system decided to show you that interface, there's nothing I can do". But that said, the device vendors may know better than developers about how users are likely to use their device.

Balance of power

There's a (relatively) simple alteration to the spec which would give developers a lot more control: allow multiple pointer values to match simultaneously to represent different connected input devices:

/* THESE ARE JUST TO ILLUSTRATE A POINT AND WON'T WORK WITH THE CURRENT SPEC! */
@media (pointer:coarse) and (pointer:fine) {
    /* both touchscreen and mouse connected */
}
@media (pointer:coarse) and not (pointer:fine) {
    /* just touchscreen connected */
}
@media not (pointer:coarse) and (pointer:fine) {
    /* just mouse connected */
}
@media (pointer:none) {
    /* no pointer devices connected */
}

Of course "coarse" could represent some other poor accuracy pointer input (e.g. a digital paintbrush), and "fine" could represent some other good accuracy device. In fact (pointer:fine) and (hover:1) could easily mean there's a hover-capable stylus connected, rather than a traditional mouse, which could be preferred by the user in quite different cicumstances.

And herein lies the problem with developers having control: we're guessing based on the information we've got. Today we base our guesses on screen size; but when these media queries come in we'd be guessing based on pointer accuracy and hover capability... which is better but still not ideal, because it doesn't tell the whole story. So do we need even more media features to get the level of control we need?

What actually determines which input a user might want to use?

I'll tell you who does know: the user. We might as well just let them choose for themselves:

Demo: Coarse/Fine UI Toggle

Check out this Pen!