Introduction
A few years ago, a client of mine said, "Andrew, these designs are great, but let's make everything twice as large, because, you know, these fat finger Americans will have a hard time clicking that.". It was a long form with lots of small elements, like checkboxes and toggles, and what he said actually made sense and led me to think about what the rules are and to what extent we should adjust our interfaces. Half of the topic is a designer's concern, but as a Frontend developer, I'll be talking about the developer's part and what we can do better while not messing with artistic choice.
Theory
What is a Fat Finger Error?
A fat finger error is a human error caused by pressing the wrong key when using a computer to input data.
Source
The term became broadly known in the finance field after it caused some serious damage on numerous occasions (see examples in the source above). In a consumer app, it can lead to a clunky user experience or rage taps even in a perfect environment and can turn out to be unusable in a non-conventional environment or for users with special needs. And we want to leave the margin for error as little as possible for our users if we want them to keep coming back to our app.
The term "target" in this topic refers to basically any interactive area in a UI that accepts a pointer action (click, touch). This could be buttons, inputs of every type, navigation links, media controls, etc.
So, generally, what's the target size requirement? According to WCAG 2.5.5 guideline, it should be at least 44x44 CSS pixels (except for targets in a sentence or block of text, i.e., links inside of text or help icons at the end of it). That's the size we will be targeting whenever possible, the recommended upper bar. As the last resort, according to WCAG 2.5.8 Minimum guideline, we should ensure a proper spacing between targets is set.
Undersized targets (those less than 24 by 24 CSS pixels) are positioned so that if a 24 CSS pixel diameter circle is centered on the bounding box of each, the circles do not intersect another target or the circle for another undersized target;
That is, technically, everything bigger than 24x24 pixels is not required to have any spacing from other targets.
There are other UI design guidelines, of course, which can even use different units of measurement (e.g., Apple Human Interface Guidelines, Google Material Design). Let's stick to pixels for web, since with other units there's a lot going on.
Practice
Single targets
As we discussed above, even an undersized target with enough spacing around it is considered acceptable. It will be easy to hit on touch devices due to the broad area they can cover with a single touch. With pointer devices, however, it will be a different case since the pointer covers only 1 pixel directly under it. That being said, if we can easily improve user experience and increase target size in this case with no drawbacks, I don't see a reason not to do it.
To increase the target size, we can simply add padding to it. In certain cases, however, this can shift around the layout, like when your target is part of a smaller flexbox. In such cases, I match the added padding with a negative margin applied to the same side. It's a simple thing that shouldn't really confuse the next developer reading your code, it's easy to calculate if there's another margin that has to be set, and it works well with Tailwind.
The alternative to margins would be adding a pseudo-element, and perhaps in some cases it will be the only way, but usually a padding + margin is more efficient and easier.
.target-element:after {
content: "";
position: absolute;
inset: 0;
width: 100px;
height: 100px;
}
Lists and composite elements
A lot of times in all kinds of navigational lists, spacing gets added to the surrounding container, leaving the items themselves small and harder to pinpoint. Whenever possible, you should prefer full-width or full-height bars for lists. Gaps between items can also be replaced with padding, but it may result in extra spacing around the container. To counteract this, once again, you can apply a negative margin to the container.
For inputs of all types (like checkbox, radio, file, etc.), we can use the <label>
element. In this case, the target area extends to the label as well, which makes a night and day difference when working with small elements like checkboxes.
Quoting MDN:
When a user clicks or touches/taps a label, the browser passes the focus to its associated input (the resulting event is also raised for the input). That increased hit area for focusing the input provides an advantage to anyone trying to activate it — including those using a touch-screen device.
You can either provide id
and for
attributes to the target element and label respectively, or an easier way would be to nest the target element inside the label.
Elements that can be associated with a <label>
element include <button>
, <input>
(except for type="hidden"), <meter>
, <output>
, <progress>
, <select>
and <textarea>
.
The last obstacle in input's accessibility I saw in various forms are prefixes/adornments that get used with them. An icon or badge that's placed on top of input and not interactive shouldn't obstruct input's target area. It could be avoided by simply adding the pointer-events: none;
CSS rule or by using <label>
as well. Similarly, a label can be used to extend the target area to include icon positions near the input, when visually it's not clear where the input's target area extends to.
Range slider
A common issue I noticed with range sliders is that the target area is limited to it's track and thumb, overlooking the area that covers the thumb's height. Some component libraries with custom range slider implementation suffer from that, at least with the setup they come with out of the box. So the first step we should do is increase the target area to thumb's height. We can go even further by extending the slider's target height beyond the thumb's height, which can be especially useful if your thumb is small.
Native HTML5 range slider (range input) supports it out of the box easily. Unfortunately, it's very limited in terms of style options and inconsistent across browsers, so it's hard to recommend it.
Below I'm comparing 3 common types of target sizes in range sliders. The last one, in my opinion, being ideal in terms of it's target size, and I think that's where we should aim. Of course it's possible that you'll be able to tweak your library of choice to this state, but in the short time I tried with some libraries, I wasn't able.
You can try it here (ignore the extra styles, and keep in mind that it looks best in Firefox):
Testing an existing codebase
Pesticide for Chrome / Pesticide for Firefox
The easiest way to test manually would be using this browser extension, which simply injects some CSS and adds an outline around all elements on the page.
You could also, of course, add your own global CSS, just keep in mind that if you are testing someone else's codebase, you'd never know if some supposedly non-interactive tags were made interactive by previous developers.
Wrap up
Check out the amazing article by Ahmad Shadeed linked below if you want a deep dive into the topic. He has the best interactive examples I've seen. I wanted to add some things from my experience and also make the topic more approachable and directed to us developers. Hence, I decided to write the first article of my own.
If you feel like something could be presented better, feel free to reach out!
Resources
https://ishadeed.com/article/target-size/
https://www.smashingmagazine.com/2022/02/fitts-law-touch-era/
Top comments (0)