クリックしやすいターゲットエリアを実装する #web_ui_devs

この記事は、「Web UI 実装勉強会 #1」での同タイトルの発表をもとにしたものです。

ターゲットエリアを広げる工夫

リンクやボタンなどのUI要素を押したときに反応する領域のことをターゲットエリアと呼びます。素朴に実装すれば、その要素の視覚的なサイズがそのままターゲットエリアになります。

しかし場合によっては、これではあまり使い勝手が良くならないことがあります。要素自体のサイズが小さいと押すことができる領域も狭くなるので、その分正確性が求められて押しづらくなります。

そういうときには、視覚的なサイズよりも余分にターゲットエリアを広げるテクニックを使います。paddingプロパティを使って要素自体のサイズを広げつつ、レイアウトが崩れないように同じ大きさのネガティブマージンを適用します。

a {
  margin: -4px;
  padding: 4px;
}

一方、プレーンなテキストリンクと違って、背景色などがついたボタンなどの場合、paddingプロパティのテクニックは少し使いづらいです。

そのような場合は、擬似要素を使って相対的な位置指定をするのが簡単です。

button {
  position: relative;

  &::before {
    position: absolute;
    inset: -6px;
    content: '';
  }
}

iOSにおけるターゲットエリア

このような工夫は僕が独自に考えたものではなくて、昔からさまざまな実装に採用されています。たとえばiOSにおいては、ナビゲーションバーのボタンではボタン自体の大きさよりも大きなターゲットエリアが確保されているそうです(参考: iPhone の当たり判定を検証した)。

ナビゲーションバーの左側のEditボタンと右側の+ボタンには、その見た目よりも大きなターゲットエリアが設定されている

ソシオメディア | iPhone の当たり判定を検証した

興味深いのは、キーボードのターゲットエリアはタイピングの途中で動的に変化するようになっていることです。ユーザーが一文字タイプするたびに、次にくる文字を予測して、キーごとに重み付けがされているのです。

QWERTYキーボードのキーの幅はかなり狭く、通常時のターゲットエリアのサイズは32ptです。

Dキーのターゲットエリアの幅は32pt

ソシオメディア | iPhone の当たり判定を検証した

しかし、「WORLD」という単語を打つつもりで「WORL」までをタイプすると、次に来る可能性が高いDキーのターゲットエリアが広がって44ptになるそうです。

Dキーのターゲットエリアの幅は44pt

ソシオメディア | iPhone の当たり判定を検証した

このような高度な実装をしてまでも、ターゲットエリアの大きさを確保することが重要なのだと思います。

ターゲットサイズの基準

とはいえ、現実的にどこまで大きくすればいいかについては、基準がなければ判断が難しいものです。

一つの目安として、WCAGにはターゲットサイズに関する達成基準が二つあります。そのなかで、最低限の基準としては24px × 24px、より高度な基準としては44px × 44pxを満たすことが定められています。また、Human Interface Guidelinesでは44pt × 44ptが基準になっています。

ガイドラインサイズ
WCAG SC 2.5.824px × 24px
WCAG SC 2.5.544px × 44px
Human Interface Guidelines44pt × 44pt

これを踏まえて、24px × 24pxの大きさは最低限確保するようにしつつ、状況に応じて44px × 44pxも達成することを目指すと考えるとよいでしょう。

押せそうな場所は押せるようにする

また別の例として、本来押せそうに見えるのに押せないようになっている実装をたまに見かけることがあります。わかりやすい例としては、チェックボックスです。チェックボタンを押せば反応するけど、そのラベルを押しても反応しないようになっていることがあります。

<input type="checkbox" /> Do you need animations?

慣習的に考えても、チェックボックスはラベルまで含めて押せるようになっているべきです。実装としては、label要素で囲えばそれを実現できます。

<label><input type="checkbox" /> Do you need animations?</label>

もう少し複雑な例として、アイコンとinput要素の組み合わせからなる検索フィールドの実装についても考えてみます。こうしたUI要素は、マークアップとして見れば複数の要素を組み合わせた複合的なコンポーネントですが、ユーザーにとっては単一の入力フィールドです。このことを意識せずに、見た目だけを再現するつもりで実装すると、限られたエリアしか押すことができない次のような実装になってしまいます。

<div class="search-field">
  <svg>...</svg>
  <input type="search" />
</div>
.search-field {
  display: inline-flex;
  gap: 8px;
  border: 1px solid;
  background-color: white;
  padding: 4px 8px;

  input {
    border: 0;
    background-color: transparent;
  }
}

これは実装モデルに引っ張られてしまったがゆえの失敗です。理想的には、複数の要素の組み合わせであることをユーザーに意識させないような実装になっているべきです。つまり、普通の入力フィールドと同じようにどこを押してもフォーカスできるようになっているのが良いでしょう。

<div class="search-field">
  <svg>...</svg>
  <input type="search" />
</div>
.search-field {
  position: relative;

  svg {
    position: absolute;
    margin: 4px 8px;
    pointer-events: none;
  }

  input {
    border: 1px solid;
    background-color: white;
    padding: 8px 8px 8px 40px;
  }
}

無闇に広げすぎない

一方、ターゲットエリアは必ずしも広ければ広いほど良いわけでもありません。

リスト項目が縦にスタックしたようなナビゲーションがあるとします。そのなかのリンクにdisplay: blockを適用すると、コンテナサイズいっぱいまでターゲットエリアが拡張されます。

a {
  display: block;
}

一見、ターゲットエリアが広がって良いことのように思えますが、別の側面から見れば、対象の要素と関係なさそうな場所を押しても反応してしまうことになります。すると、「リンクを押すつもりはないのに、意図せず押したことになってしまった」ということが起こり得ます。

この改善例としては、width: fit-contentなどを適用して必要以上に伸び広がらないように制御するのが良いでしょう。またpaddingのテクニックも併用して、周辺に少しだけ広げる工夫もするとなお良いです。

a {
  display: block;
  margin-inline: -12px;
  padding-inline: 12px;
  width: fit-content;
}

似たような例として、入力フィールドのラベルのターゲットエリアがあります。レイアウトの都合でdisplay: blockを適用することはよくありますが、その場合も同様の問題が起こります。

label {
  display: block;
}

こうしたときにも、width: fit-contentなどを適用して範囲を制御するのがよいと思います。

label {
  display: block;
  width: fit-content;
}

今回の勉強会についての余談

今回のこの勉強会に参加したのは、開催者のKatashinさんが以前投稿していた「UI の実装に関する勉強会をやりたい」という問題意識に共感したからだ。

最近また勉強会に参加するようになって色々と行っているうちに、ふと UI の実装に関する勉強会ってほとんどないなと思った。UI デザインはちらほら見かけるけど、UI 実装は見かけない。

たいてい TypeScript、Vue、Biome みたいに言語、ライブラリ、ツールをテーマにしたものが多くて、UI を切り口にしているものを見かけない。もちろん、他のテーマの勉強会で UI を絡めた話がある場合もあるけど、UI 実装をテーマに据えた会でいろいろな話を聞いてみたい。

UI の実装に関する勉強会をやりたい

同日に投稿されていた、橋本麦さんの「Jul 24, 2025: 詰め方の問題」にも感化された部分がある。

結局のところ、ぼくが気になっているのは、ものごとを媒介する関係性や構造ばかりが語られて、肝心のそれ自体——グラフィックであれ、アニメーションであれ、画面に現れる表層的な“何か”そのものが、語られることなくどこかへ押しやられていることだ。もちろん、それをめぐる構造、物語性、組織や経済がどう影響しているかは、無視できるわけじゃない。でも、だからといってそれ「ばかり」に意識を向けるのは、Lev Manovichが言うように、画面の「出力」だけを見てその背後にあるプログラムのアーキテクチャを問わないのと同じくらい片手落ちだ。それは生存戦略として間違っちゃいないにせよ、グラフィックデザイン文化としては貧しいと思う。

Jul 24, 2025: 詰め方の問題

個人的には、自分の近辺のコミュニティで、UIそのものについて語られる機会が少ないと思っていた。みんなある程度のキャリアを経ると、そういう手前の話は「通過済み」のものとして理解されてしまうのかもしれない。けれど僕にとっては最初と変わらず喫緊の問題だし、いつまで経っても、世の中に新たな出来の悪いUIが生み出され続けていることに辟易としている。

また、開発者のUIに対する無頓着さについても気になっていた。開発者としてコードを書いていると、何かを形にするための方法にばかり視点が向いてしまうことがある。しかしその方法としての妥当性の前に、形にしようとしているそのものに目を向けることが重要だし、それに付き従って構造ができるのだ。ダメなものの構造を強化しても仕方がない。これは分業体制下において抜け落ちがちな意識かもしれない。

だからこそ、UIのデザイン意図と実装が交差するような話をしたいと思った。本来デザインと実装の垣根はないが、何かしらの肩書きのもとで植え付けられた意識が、そこに壁を作っている。そうしたナンセンスな区分けにとらわれずに、それそのものについてフラットな視点で考えられるようにしたい。

こういう考え方がもっと広められると良いし、そのような機会があれば連帯したい。次回も開催されるようなので参加したいと思う。

あと、久しぶりに会ったterkelさんに「相変わらずfundamentalな話してる」と評されたのがうれしかった。