Expanding your touch targets – Nicole Sullivan

By admin
When developers create a website, an important concern is that the tap targets are sufficiently big for all different kinds of input devices. This includes mouse pointers, which are fairly accurate, but can also include fingers, thumbs, or assistive tech.

Today
DATE

I learned that if you live in the

midwest
LOC

in

winter
DATE

, it can also include noses!

Given the variation in devices and input mechanisms, how does the browser determine what you clicked on?

TL;DR Browsers kind of expand the tap target of elements and try to find the element the user intended to click. It works slightly differently in each browser, but the end result is roughly the same: Browsers assist users who are unable to click perfectly given the combination of their circumstances and abilities.

What can you do as a developer to help this work as accurately as possible? When you have clickable “targets”, you should follow the minimum target size guidelines from WCAG

2.2
CARDINAL

. This gives you a couple options:

Size your clickable targets at least 24px by 24px. If your design requires a smaller clickable target, keep any other clickable elements at least 12px from the center of the target.

The failure might seem a bit arbitrary until we zoom in. We can see that the point of the next clickable star extends 2px into the space of the

first
ORDINAL

star because there isn’t enough space between them and they are only 20px wide.

You don’t need to worry about inline elements like links in the middle of sentences, and there are more exceptions in the guidelines, but these

3
CARDINAL

are the ones you need to understand for this article.

The browser doesn’t change anything in the page visually. It all happens behind the scenes so users who don’t quite hit tap targets don’t have a frustrating experience on the web.

You can definitely stop here. You know what you need to know to design a site with good tap targets. But, for those of you who want to go deeper, let’s get into how this works in browsers.

This was my

first
ORDINAL

time reading

C++
PERSON

, so I probably misunderstood a few things. Corrections welcome!

Definitions


First
ORDINAL

a few definitions. I’ll use these throughout, even though different browsers have their own language for it. In this example, this giant stubby finger is attempting to click the yellow star, but it misses.

Touch point – The location where a user initiates a touch, tap, click, swipe, or other input. In this photo, the turquoise dot at the center of the finger. In

Blink
PERSON

it is called a touch point. In

Gecko
GPE

, it is an event position.

– The location where a user initiates a touch, tap, click, swipe, or other input. In this photo, the turquoise dot at the center of the finger. In

Blink
PERSON

it is called a touch point. In

Gecko
GPE

, it is an event position. Touch target – an element the user can interact with. Includes things like links and buttons. In this photo, it is the yellow star. In

Blink
PERSON

it is called a Candidate. In

Gecko
GPE

it is called a

Frame
PRODUCT

.

– an element the user can interact with. Includes things like links and buttons. In this photo, it is the yellow star. In

Blink
PERSON

it is called a Candidate. In

Gecko
GPE

it is called a Frame. Event radius – The invisible expanded area around a touch target that can also be clicked or tapped. In some browsers the touch point is expanded rather than the touch target. It is made up of

two
CARDINAL

things, the size of the physical touch radius (how big your thumb was) and any ways the browser either expands or shrinks that area automatically to optimize user outcomes. In this picture it is the white dashed line. In

Chromium
ORG

it is called a hit rectangle.

How do browsers find potential touch targets?

Browsers have different heuristics for finding elements that are touch targets and excluding elements that are not. This table is the criteria I found in the codebases, but probably not the complete set. (more to come for webkit!)


Criteria Chromium Firefox Webkit
ORG

(incomplete) Responds to tap (mouse move and click) x x Focusable item x – Exclude focusable items – – x* Excludes iframes x – :active / :hover set x x role=button or role=key – x Sets touch start or end – x Controls (forms) x x Editable – x Excludes stylus and other editable areas x – Set CSS cursor:pointer property – x Exclude cursor:auto children of cursor pointer – x Listeners (like mousedown and

mouseup
PERSON

) x x Exclude pseudo elements x – Visited links – x Exclude large touch targets – – x Exclude media controls – – x Touch target criteria found in each of the

3
CARDINAL

browser engines. * seems unlikely to be true, probably a misreading of the code on my part.

In

Chromium
ORG

, the main heuristic for candidates is called

NodeRespondsToTapGesture
ORG

which is about whether it is focusable, affected by :hover or :active , or has listers for things like mousedown ,

mouseup
PERSON

, and click .

Firefox considers a few different characteristics to determine which elements are candidates, like whether it is editable, has listeners, has a role=button or role=key , sets the

CSS
ORG

cursor property, sets touch start or end, or if it is a link. Additionally, if you set the cursor to auto, it is removed from this list because the developer probably didn’t intend for the element to be clickable. See GetClickableAncestor .

From this set of criteria, browsers build a list of potential touch targets that might be the closest to the touch point.

Which touch target wins?

How do browsers decide which event radius is closest to the touch point? Again, with a combination of heuristics and some math.

Chromium

In

Chromium
ORG

, we compute an hit rectangle based on the physical touch radius of the touch points. See WebGestureEvent::TapAreaInRootFrame . Then, we search for any candidates which overlap this area and choose the best one based on a combination of distance and size of target. See FindBestCandidate . Distance in is the best (shortest) of area of overlap (works well for long links) and percentage of overlap which gives a higher confidence for small targets. Chromium currently excludes pseudo elements.

Which candidate is chosen also varies based on the detected size of the tap. This tap varies from device to device, tap to tap, and finger to finger. Page zoom ratio and device-pixel-ratio (high DPI) can also affect the decision.

Firefox

After

Gecko
ORG

finds a set of candidate frames, they determine which one the user probably intended to interact with.

First
ORDINAL

, they expand the touch radius by a certain number of millimeters based on the user’s device. See

ui.touch.radius
ORG

to look for the value for devices you support. Then, if there is a clickable element directly under the event position,

Firefox
ORG

uses that. otherwise they find all the frames that intersect a radius around the event position and calculate the closest by distance. CSS transforms are taken into account. See GetClosest .

What do they mean by closest? In their own words:



GetClosest
WORK_OF_ART

() computes the transformed axis-aligned bounds of each candidate frame, then computes the

Manhattan
GPE

distance from the event point to the bounds rect (which can be

zero
CARDINAL

).” Gecko

I’ll be honest, I had to look up the

Manhattan
GPE

distance. It is the distance between

two
CARDINAL

points if you travelled the distance at right angles. Imagine a taxi in

manhattan
GPE

going diagonally across the city. It would need to turn from street to street to cover that diagonal distance. That is the

Manhattan
GPE

distance.

This isn’t anything particularly new. Most of the code

Firefox
ORG

uses to “fluff out” touch and click targets was written over

a decade ago
DATE

. [bug]


Webkit

Webkit
PRODUCT

starts by determining selectability and calculating a bunch of different information about potentially selectable elements. It is still unclear to me what it uses of that information for… but I’ll fill in more as I find my way through the code.

As I understand it,

Webkit
ORG

expands the touch point rather than the tap target but I haven’t found this in code yet.

What can you do?

The biggest thing you can do to work in concert with browsers is to keep

at least
CARDINAL

24px of space around your touch targets. This means, that from the center of your touch target, there should be no other touch targets within a 12px radius. This can be 24px wide touch targets, or 20px wide touch targets with 2px of space between it and the edge of another touch target. Browsers heuristics to expand the event radius and the flexibility in the minimum target size guidelines work together to allow developers to create well designed sites that don’t compromise interactivity.

Thanks!

Thanks to

Adrian
PERSON

for asking questions and creating a codepen that started this investigation.


Two
CARDINAL

people pointed me in the right direction.


Emilio
PERSON

at

Mozilla
ORG

.

Code is here: https://t.co/nzxlrZn6wC

Things like whether you’re editable, the css cursor property, whether you have listeners, whether you’re a link, and whether you have `role=button` or `role=key`.

Main function is here: https://t.co/wyLT2J1jjW —

Emilio
PERSON

(@ecbos_)

September 13
DATE

, 2023

And

Rob Flack
PERSON

at

Google
ORG

for his responses to my many queries.