Touch

Interaction Media Features

While it’s still true that You Can’t Detect A Touchscreen, the Interaction Media Features media queries can come in handy in edge cases. Still, don’t assume too much about a device, as both the link above and the source for this emphasize.

Thanks to the W3C CSS Working Group and the CSS community, we have a cleaner solution.

On the Media Queries Level 4 Working Draft, there is a spec for Interaction Media Features that includes three definitions:

These provide the capability to query a document based on the presence and accuracy of the user’s pointing device and whether it has the ability to hover over elements.

Let’s take a closer look at each one:

Pointing Device Quality: The pointer Feature

The pointer media feature is used to query about the presence and accuracy of a pointing device such as a mouse. If a device has multiple input mechanisms, the pointer media feature must reflect the characteristics of the “primary” input mechanism, as determined by the user agent.” - W3C

The key word here is “accuracy” of the pointing device.

  • A mouse or a drawing stylus is very accurate and defines the value of fine.
  • A finger or a Kinect peripheral isn’t, and takes the value of coarse.

Therefore, we can adapt our UI elements to the user’s pointer capabilities. This is useful for making hit areas larger, if the user’s main input mechanism is a finger.

Code language: CSS

/* The primary input mechanism of the device includes a pointing device of limited accuracy. */
@media (pointer: coarse) { ... }
 
/* The primary input mechanism of the device includes an accurate pointing device. */
@media (pointer: fine) { ... }
 
/* The primary input mechanism of the device does not include a pointing device. */
@media (pointer: none) { ... }

An example use case for this query is to size the click area of a checkbox or radio.

Hover Capability: The hover Feature

The hover media feature is used to query the user’s ability to hover over elements on the page. If a device has multiple input mechanisms, the hover media feature must reflect the characteristics of the “primary” input mechanism, as determined by the user agent.” - W3C

It’s important to notice that it only evaluates the primary input mechanism. If the primary input mechanism is not able to hover, but the secondary input can, then the query will resolve to none:

For example, a touchscreen where a long press is treated as hovering would match hover: none.” - W3C

  • A touch screen device, where the primary pointer system is the finger and can’t hover, will take the value of none.
  • A device where the primary input is a mouse and can easily hover parts of the page takes the value of hover.

Code language: CSS

/* Primary input mechanism system can 
   hover over elements with ease */
@media (hover: hover) { ... }
 
/* Primary input mechanism cannot hover 
   at all or cannot conveniently hover 
   (e.g., many mobile devices emulate hovering
   when the user performs an inconvenient long tap), 
   or there is no primary pointing input mechanism */
@media (hover: none) { ... }

A good use of this query is a drop-down menu.

Rare Interaction Capabilities: The any-pointer and any-hover Features

On devices that are both touch and have a mouse or a stylus, like the Microsoft Surface, the hover and pointer media query will evaluate the primary input mechanism only.

As Andrea Giammarc pointed out, his Dell XPS 13” touch takes the value of fine, even though it does have a touch screen because the primary input mechanism is a mouse.

[…]

If we want a device like that to take the value of coarse or hover, we can use the Rare Interaction Capabilities.

The any-pointer and any-hover media features are identical to the pointer and hover media features, but they correspond to the union of capabilities of all the pointing devices available to the user. More than one of their values can match, if different pointing devices have different characteristics. They must only match none if all of the pointing devices would match none for the corresponding query, or there are no pointing devices at all.” - W3C

Code language: CSS

/* One or more available input mechanism(s) 
   can hover over elements with ease */
@media (any-hover: hover) { ... }
 
/* One or more available input mechanism(s) can hover, 
   but not easily (e.g., many mobile devices emulate 
   hovering when the user performs a long tap) */
@media (any-hover: on-demand) { ... }
 
/* One or more available input mechanism(s) cannot 
   hover (or there are no pointing input mechanisms) */
@media (any-hover: none) { ... }
 
 
/* At least one input mechanism of the device 
   includes a pointing device of limited accuracy. */
@media (any-pointer: coarse) { ... }
 
/* At least one input mechanism of the device 
   includes an accurate pointing device. */
@media (any-pointer: fine) { ... }
 
/* The device does not include any pointing device. */
@media (any-pointer: none) { ... }

Browser Support Isn’t Bad at All!

Even though this is a working draft, it has pretty good support.

My simple test proved successful on Chrome, Chrome for Android, Safari, Edge, Opera, Samsung browser, and Android Browser, but it didn’t work on [Firefox], Opera Mini or IE.

[…]

I think we are ready to use this feature, and as [Firefox] adds support for it and IE dies once and for all, we will have full support.

You Can't Detect A Touchscreen

Whatever you may think, it currently isn’t possible to reliably detect whether or not the current device has a touchscreen, from within the browser.

And it may be a long time before you can.

Let me explain why…

Boxed in

The browser environment is a sandbox. Your app’s code can only get at things the browser wants you to, in order to limit the damage a malicious website can cause.

This means that the only information about the system you can get is what the browser exposes to you, in the form of HTML, CSS and JavaScript APIs. To determine if a system supports a certain feature, we can a) see if a certain API is present, or b) see if it actually does the right thing.

Historically, two browser features have been used for “touchscreen detection”: media queries and touch APIs. But these are far from foolproof.

Walk with me.

Device width media queries

Mobiles have small screens and mobiles have touchscreens, so small screen equals touchscreen, right?

[…]

So, so very wrong. Large tablets and touchscreen laptops/desktops have clearly proven this wrong. Plus thousands of older mobile handset models had small non-touch screens. Unfortunately, sites applying the mantra “If it’s a small screen, it’s touch; if it’s a big screen, it’s mouse-driven” are now everywhere, leaving tablet and hybrid users with a rubbish experience.

Touch APIs

[…]

If the browser supports events like touchstart (or other events in the Touch Events API spec) it must be a touchscreen device, right?

[…]

Well, maybe. The problem is, no one ever said that a non-touch device can’t implement touch APIs, or at least have the event handlers in the DOM.

Chrome 24.0 shipped with these APIs always-on, so that they could start supporting touchscreens without having separate “touch” and “non-touch” builds. But loads of developers had already used detects like the example above, so it broke a lot of sites. The Chrome team “fixed” this with an update, which only enables touch APIs if a touch-capable input device is detected on start-up.

So we’re all good, right?

Not quite.

An API for an API

The browser is still quite a long way from the device itself. It only has access to the devices via the operating system, which has it’s own APIs for letting the browser know what devices are connected.

While these APIs appear to be fairly reliable for the most part, we recently came across cases whereby they’d give incorrect results in Chrome on Windows 8… they were reporting presence of a touchscreen (“digitizer”), when no touchscreen was connected.

Firefox also does some kind of similar switching and it appears to fail in the same cases as Chrome, so it looks like it might use the same cues – although I can’t profess to know for sure.

It appears certain settings and services can mess with the results these APIs give. I’ve only seen this in Windows 8 so far, but theoretically it could happen on any operating system.

Some versions of BlackBerry OS have also been known to leave the touch APIs permanently enabled on non-touch devices too.

So it looks like the browser doesn’t know with 100% confidence either. If the browser doesn’t know, how can our app know?

Drawing a blank

Assuming the presence of one of these touch APIs did mean the device had a touchscreen… does that mean that if such a touch API isn’t present then there definitely isn’t a touchscreen?

Of course not. The original iPhone (released in 2007) was the first device to support Touch Events, but touchscreens have been around in one form or another since the 1970s. Even recently, Nokia’s Symbian browser didn’t support touch events until version 8.2 was released last year.

IE 10 offers the (arguably superior) Pointer Events API on touch devices instead of the Touch Events spec, so would return false for the ontouchstart test.

[…]

Neither Safari nor Opera has implemented either touch API in their desktop browsers yet, so they’ll draw a blank on touch devices too.

Without dedicated touch APIs, browsers just emulate mouse events… so there are loads of devices kicking about with touchscreens which you simply can’t detect using this kind of detection.

[…]

You’re doing it wrong

In my opinion, if you’re trying to “detect a touchscreen” in the first place, you’re probably making some dangerous assumptions.

[…]

So what should I do?

For layouts, assume everyone has a touchscreen. Mouse users can use large UI controls much more easily than touch users can use small ones. The same goes for hover states.

For events and interactions, assume anyone may have a touchscreen. Implement keyboard, mouse and touch interactions alongside each other, ensuring none block each other.

Large, custom, accessible checkboxes and radio buttons on GOV.UK

Early in the development of GOV.UK we observed in research how a majority of users would click on radio button or checkbox controls rather than on their labels, despite the fact that the labels are much bigger and therefore easier to click (see Fitt’s Law).

[…]

We reasoned that this was because users didn’t know whether or not they could click on the labels. Many websites don’t let you click on labels, so choosing to always click on the control is perfectly rational user behaviour.

[…]

First we thought we’d try to make it really obvious that you could click our labels, so we coloured them grey and made them respond to the mouse hovering over them.

We thought this would work, so we rolled out the design across services on GOV.UK. We saw again and again though in lab research that most users still clicked on the controls.

[…]

In our latest iteration we’ve replaced the native browser controls with custom ones, which all our supported browsers will get.

We’ve also removed the grey background, as it did not have the effect on user behaviour that it was intended to.