A new way to test for touch devices without JavaScript: Enter the pointer media query

cooty

Cooty

Posted on September 9, 2023

A new way to test for touch devices without JavaScript: Enter the pointer media query

One of the age-old problems of responsive web-design is how do we distinguish between mobile and desktop.
Of course your gonna say that this is a trivial problem: We have media queries, dummy!

@media (max-width: 768px) {
  /* Styling goes here for handheld, ie "mobile" devices */
}
Enter fullscreen mode Exit fullscreen mode
@media (min-width: 1200px) {
  /* Styling goes here for laptops and desktops */
}
Enter fullscreen mode Exit fullscreen mode

So that's it we can call it a day and move on with our lives, right?
Not quite!

Let's start with the fact that the above code (and most other media queries we write on a day to day basis) carry with them a lot of assumptions.

We assume that it is an iPad or other similar tablet if the viewport is less the or equal to 768px but maybe our user just squished the window of his browser on his 8K ultra-wide monitor so that he can put several windows next to each other.

We also assume that a device with a display that's at last 1200px wide is some sort of laptop, however there are plenty of tablets that are more then 1200px wide in landscape mode.

These assumptions are usually safe when we're just talking about layout and we try to find different breakpoints to tailor our design to different screen sizes.

But the problems start when we want different behavior for mobile devices. Like say we want to show a small dropdown calendar on desktop but on mobile we want a pop-up date picker component.

The gist of the problem is that sometimes we need different UI for the devices where the primary method of input is touch and the ones where it's a mouse.

Until recently we had to result to various JS hacks to detect touch capabilities of a device. For example here's one popular snippet:

function isTouchDevice() {
  return (
    "ontouchstart" in window ||
    navigator.maxTouchPoints > 0 ||
    navigator.msMaxTouchPoints > 0
  );
}
Enter fullscreen mode Exit fullscreen mode

There's two problems with this approach

  1. They are flaky and unreliable. We can only test for the presence of touch events implemented by the browser but that does not necessarily imply that the device has a touch screen.
  2. You need client-side JS for this to run, if you make the interactions depend on some JS to run that might result in a bad experience when the JS has not yet downloaded. You would want these sort of tests to run immediately as soon as the user can interact with the page

However now we have an actual media query to test what pointer type the device supports.

The syntax looks like this

@media (pointer: none|coarse|fine) {
  /* Some code based on the supported pointer value */
}
Enter fullscreen mode Exit fullscreen mode

The value is an enum with three possible values as defined in the spec.

none

The primary input mechanism does not include a pointing device.

coarse

The primary input mechanism includes a pointing device of limited accuracy, such as a finger on a touchscreen.

fine

The primary input mechanism includes an accurate pointing device, such as a mouse.

Using this query we can for example make checkboxes and radio buttons larger for devices that have a coarse pointer.

Of course we can also use this query from JS to manipulate the behavior of our UI or load entirely different components optimized for touch versus mouse inputs.

If you were wondering about "Can I already use this in production, how is this thing supported?" I have good news for you: The caniuse table for the feature is quite nice and green!

Also MUI X UI library uses this method in their date picker component.

Hope you can utilize this new feature of the web platform to make your UI code more elegant and our users happier!

💖 💪 🙅 🚩
cooty
Cooty

Posted on September 9, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related