Updating to a touch-friendly UI

Published by marco on

Updated by marco on

I was recently redesigning a web page and wanted to make it easier to use from touch-screen browsers. Links made only of text are relatively easy to click with a mouse, but tend to make poor touch targets. If the layout has enough space around the link, this can be remedied by applying CSS.

The basic box

Suppose we have a box with three links in it, as shown to the right.

Setting the height

The first step is to make this box taller, so the logical thing to do is to set the height. We’ll have to pick a value, so set height: 40px on the gray box.

Aligning vertically

This isn’t exactly what we want, though; we’d rather have the vertical space equally distributed. Also, if you hover over the links, you can see that the space below the text is not active. Maybe we can try to add vertical-align: middle to align the content.

Unfortunately, this doesn’t have the desired effect. The vertical-align property works when used this way in table cells, but otherwise has no effect for block elements. Knowing that, we can set display: table-cell for the gray box.

And now the box has become longer, because the 50% width of the box is calculated differently for table cells than for regular boxes (especially when a table cell is found outside of a table).

Relative positioning

Let’s abandon the vertical-alignment approach and try using positioning instead. Set position: relative and top: 25% to center the links vertically.

Now that looks much better, but the space above and below the links is still not active. Perhaps we can use the height trick again, to make the individual links taller as well. So we set height: 100% on each of the links.

We didn’t get the expected result, but we should have expected that: the links are inline elements and can only have a height set if we set display: inline-block on each link as well. We use inline-block rather than block so that the links stay on the same line.

The links are now the right size, but they stick out below the gray box, which isn’t what we wanted at all. We’re kind of out of ideas with this approach, but there is another way we can get the desired effect.

Positive padding and negative margins

Let’s start with the original gray box and, instead of choosing a random height as we did above—40px—let’s set padding: 8px on the gray box to make room above and below the links.

With just one CSS style, we’ve already got the links nicely aligned and, as an added benefit, this technique scales even if the font size is changed. The 8-pixel padding is preserved regardless of how large the font gets.[1]

This approach seems promising, but the links are still not tall enough. The naive approach of setting height: 100% on the links probably won’t work as expected, but let’s try it anyway.

It looks like the links were already 100% of the height of the container; in hindsight it’s obvious, since the height of the gray box is determined by the height of the links. The 100% height refers to the client area of the gray box, which doesn’t include the padding.

We’d actually like the links to have padding above and below just as the gray box has. As we saw above, the links will only honor the padding if they also have display: inline-block, so let’s set that in addition to padding: 8px.

We’re almost there. The only thing remaining is to make the vertical padding of the links overlap with the vertical padding of the gray box. We can do this by using a negative vertical margin, setting margin: -8px.

We finally have the result we wanted. The links are now large enough for the average finger to strike without trying too hard. Welcome to the CSS-enabled touch-friendly world of web design.

The code for the final example is shown below, with the sizing/positioning styles highlighted:

  background-color: gray;
  border: 1px solid black;
  border-width: 1px 0;
  width: 50%;
  text-align: center;
  padding: 8px 0;

.gray-box a
  background-color: #8F8F8F;
  display: inline-block;
  padding: 8px 20px;
  margin: -8px 0;

<div class="gray-box">
  <a href="#" style="color: goldenrod">First</a>
  <a href="#" style="color: gold">Second</a>
  <a href="#" style="color: yellowgreen">Third</a>

[1] Naturally, we could also use .8em instead and then the padding will scale with the font size. This would work just as well with the height. Let’s pretend that we’re working with a specification that requires an 8-pixel padding instead of a flexible one.