本文へ移動
UI/UX

ボタンの状態デザインの渡し方。フォーカス・無効・読み込み中・エラーを NG/OK で確かめる

公開 読了まで 約15分

( この記事の要点 )

  1. 画面の一枚には状態が描かれないので、実装する人も AI も推測で埋めてしまう
  2. 抜けやすいのはフォーカス・無効・読み込み中・エラーの4つ。NG/OK の作例と WCAG の基準で見分ける
  3. 状態ごとの数値と文言を短い仕様文にして渡す。無効のボタンは「作らない」も選べる

Figma で丁寧に作ったボタンが、実装されて戻ってきたら、押したあとの見た目がなかった。キーボードで操作すると、どこを選んでいるのか分からない。送信中にボタンの幅がふっと縮む。AI に画面を組ませたら、無効のボタンが薄い灰色で、なぜ押せないのか誰にも分からない。ひとりでデザインを担当していると、こうした「デザインしていない部分」を、毎回あとから見つけて直すことになりがちです。

先に結論です。ボタンや入力欄の「状態」は、画面の一枚とは別に、状態の一覧と短い仕様文で渡します。とくに抜けやすいのは、フォーカス(キーボードで選んだとき)、無効、読み込み中、エラーの4つです。この記事では、その4つを NG と OK の作例で比べ、根拠になる WCAG の基準と、そのまま使える仕様の書き方をまとめました。

なぜ「押したあと」や「読み込み中」は抜けるのか

Figma の画面は、ある瞬間を止めた一枚です。ボタンには、カーソルを乗せたとき、キーボードで選んだとき、処理を待つ間など、いくつもの姿がありますが、画面に描かれるのはふつう1つだけです。実装する人は、描かれていない姿を推測で埋めます。忙しければブラウザやライブラリの初期値のまま進みますし、AI に組ませれば、書かれていない部分は AI がそれらしく決めてしまいます。

道具の側も変わりつつあります。Figma は2026年10月の Config India で、チームのデザインの決まりを文章で書いて、人とエージェント(指示を受けて作業を進める AI)が参照できる「Specs」を発表しました。有料プランでのオープンベータ(試験提供)です。公開されたデザインライブラリにエージェント向けの指針を付ける「Guidelines」もオープンベータで始まっています。どの道具を使うにしても、状態の決まりを文字で残しておくことが、これまで以上に効いてきます。

ボタンと入力欄に用意する状態の一覧

まず、どの状態を作るかを決めます。ボタンと入力欄なら、次の表が出発点になります。「必ず作る」と「必要なときに作る」を分けておくと、作業量を抑えられます。

状態いつ作るか見た目で決めること
通常(default)何もしていないとき必ず部品だと分かる形。見分けるのに必要な線や面は、周りと 3:1 以上
ホバー(hover)カーソルを乗せたとき必ず(パソコン)少しの変化でよい。スマートフォンにはない
フォーカス(focus-visible)キーボードで選んだとき必ずはっきり見える印。ホバーと別の見た目にする
押している間(pressed)クリック・タップの間必ず押せたと分かる変化
読み込み中(loading)押したあと、処理を待つ間送信・保存のボタン幅を変えない。何をしているかを文字で残す
無効(disabled)今は押せないときなるべく作らない使うなら、理由をすぐ近くに書く
エラー(error)入力欄の値に問題があるとき入力欄は必ず色だけに頼らず、文字で何が違うかを書く
送信ボタンの状態の一覧(Button / Primary)。最小幅 160px。通常(default)は黒い「送信する」。ホバー(hover)は少し明るい黒で、カーソルが乗っている。フォーカス(focus-visible)は外側に黒い線。押している間(pressed)はさらに明るい灰黒。読み込み中(loading)は回る印と「送信中…」。無効(disabled)は点線の枠に「使わない」。
送信ボタンの状態一覧。幅はどの状態も同じにしています。説明用の作例です(実寸の約1.75倍。フォーカスリングは見やすくするため2倍で表示)。

変化の強さの目安がほしいときは、Google の Material Design 3 の値が参考になります。公式のデザイントークン(色や大きさなどの決まりを名前と値にしたもの)では、部品の上に重ねる色の膜(state layer)の不透明度を、ホバー 8%、フォーカス 10%、押している間 10%、ドラッグ中 16% にしています。無効の state layer の値は 38% です。

なお、CSS の :focus と :focus-visible は違います。:focus-visible は、ブラウザが「フォーカスの印を見せるべき」と判断したときだけ当たります。Chromium 153 で試したところ、キーボードの Tab キーで選んだボタンには当たり、マウスでクリックしたボタンには当たりませんでした。デザインでも「キーボードで選んだときの見た目」として、ホバーとは別に作っておくと、実装とずれません。

NG/OK で見る、抜けやすい4つの状態

1. フォーカス:フォーカスリングが見えない、ホバーと同じ

キーボードで選んだときに出る枠を、フォーカスの印(フォーカスリング)と呼びます。よくあるのが、ブラウザの初期の枠を消して、代わりに薄い影や淡い色を付けるやり方です。デザイン上はきれいに見えますが、地の色との差が小さいと、キーボードで操作する人には、今どこにいるのかが分かりません。

WCAG 2.2 の 2.4.7「フォーカスの可視化」(レベル AA)は、キーボードのフォーカスの印が見えることを求めています。1.4.11「非テキストのコントラスト」(AA)の解説では、フォーカスの印も、隣り合う色と 3:1 以上の差が必要な例として扱われています。さらに上の段階の 2.4.13「フォーカスの外観」(AAA)は、2px の太さの枠に相当する広さがあり、フォーカスの前と後で 3:1 以上の差があることを求めています。

OK の作例では、墨色の 2px の線を、ボタンから少し離して外側に引いています。ボタンの色に左右されず、白い地の上でははっきり見えます。

フォーカスの印の NG と OK。NG ではホバーとフォーカスのボタンがほぼ同じに見え、フォーカスは淡い水色の影だけで「印が見えない」。OK ではフォーカスのときにボタンの外側に黒い線が出て、「2px の線」と示している。
フォーカスの印は、ホバーと別の見た目で、はっきり見える線にします。説明用の作例です(実寸の約1.75倍。フォーカスリングは見やすくするため2倍で表示)。

2. 無効:なぜ押せないのか分からない

必須の項目が埋まるまで送信ボタンを薄い灰色にして押せなくする作りはよく見かけますが、押せない理由が書かれていないと、使う人はそこで止まってしまいます。

デジタル庁デザインシステムは、ボタンを無効にする設計を考えるときは「そもそも無効化する必要があるかを注意深く確認してください」としたうえで、送信ボタンは無効にせず、押されたときにエラーメッセージでやるべきことを案内するよう勧めています。どうしても無効にするなら、すぐ近くに、なぜ無効なのか、どうすれば押せるようになるのかを具体的に書く、としています。

無効の部品は、WCAG の 1.4.3 と 1.4.11 のコントラストの決まりから外れます。決まりの上では薄くしてもかまわない、ということですが、薄いほど読めなくなるのも事実です。デジタル庁デザインシステムは、背景との差を 3:1 以上にすると無効に見えないことがあり、3:1 未満だとそもそも見えない可能性がある、という矛盾を指摘しています。見た目の工夫だけで解決しにくいので、次の節の「無効を作らない」選び方が効いてきます。

無効のボタンの NG と OK。どちらも「メールアドレス(必須)」の欄が空。NG では「送信する」が薄い灰色で押せず、「理由が書かれていない」。OK では「送信する」は押せる黒いボタンのままで、すぐ下に「必須の項目を入力すると送信できます」とあり、「条件をすぐ近くに」と示している。
ボタンは無効にせず押せるままにし、送信できる条件をすぐ近くに書きます。説明用の作例です。

3. 読み込み中:ボタンの幅が変わる、何をしているか分からない

押したあと、ボタンの文字をスピナー(くるくる回る印)に置き換えると、文字の分だけボタンの幅が縮み、周りの部品がずれます。文字が消えるので、何を待っているのかも分からなくなります。

OK の作例では、ボタンの幅を最初の幅のまま固定し、回る印を文字の左に足して、文字を「送信中…」に変えています。GitHub のデザインシステム Primer も、アイコンの付いたボタンでは、読み込み中に回る印がアイコンの位置だけを置き換え、ボタンの文字は見えたままにする、と説明しています。読み上げソフトを使う人には見た目の変化が伝わらないので、「送信しています」のような文を、読み上げられる場所(role="status" の要素など)に出すことも仕様に書いておきます。

読み込み中の NG と OK。NG では、押す前は幅 160px の「送信する」が、押したあとは回る印だけになり「48px に縮む」。OK では、押したあとも「160px のまま」で、回る印と「送信中…」が出ている。
読み込み中もボタンの幅を変えず、何をしているかを文字で残します。説明用の作例です(幅は実寸の値)。

4. 入力欄のエラー:赤い枠だけで伝える

枠の色を赤に変えるだけのエラー表示は、色の違いが分かりにくい人には伝わりません。WCAG の 1.4.1「色の用途」(A)は、色だけで情報を伝えないことを求めています。3.3.1「エラーの特定」(A)は、入力のエラーを自動で見つけたときに、その箇所を特定し、何が違うのかを文字で説明することを求めています。

OK の作例では、枠を赤くしたうえで、入力欄のすぐ下に印と文で「@ のあとが入っていません」と、何が違うのかを書いています。直し方まで一言で書けるなら、「例:[email protected]」のように添えるとさらに親切です。赤い色を使うこと自体は問題ありません。色に加えて、形と文字でも伝えるのがポイントです。

メールアドレスの入力欄のエラーの NG と OK。どちらも「name@」と入力され、枠が赤い。NG は「赤い枠だけ」。OK では、欄の下に印と「@ のあとが入っていません」の文があり、「印と文で伝える」と示している。
エラーは枠の色に加えて、印と「何が違うか」の文で伝えます。説明用の作例です(アイコンは Material Symbols、Apache License 2.0)。

無効(disabled)は「作らない」も選べる

無効の扱いについて、次の4つのデザインシステムは、いずれも「なるべく使わない」としています。

  • デジタル庁デザインシステム:送信ボタンを無効にする必要はない。作業が済んでいなければ、エラーメッセージで案内する
  • SmartHR Design System:無効状態のボタンは「できるだけ使わないように」。理由を置く場所がないときは、理由を表示する disabledReason を検討する
  • Atlassian Design System:とくにフォームでは、ボタンを無効にせず押せるままにして、入力の確認とエラーで伝える
  • Primer(GitHub):無効のボタンは、キーボードで操作する人が使えなくなるので避ける。見た目だけ無効にして操作は受け付ける inactive を別に用意している

理由のひとつは、HTML の disabled 属性を付けたボタンが、Tab キーで移動する順番から外れることです。W3C の APG(WAI-ARIA の作り方の手引き)のキーボード操作のページは、フォーカスできない無効の部品は、読み上げソフトを使う人に見つけてもらいにくい、と説明しています。見つけてもらう必要があるときは、aria-disabled="true" を使う方法があります。こちらはフォーカスできるまま「無効」と伝えますが、押されたときの動きを止めるのは作り手の仕事です。とはいえ、まず検討したいのは無効にしない作りです。

デザイナーが仕様に書くのは、「押されたらどうするか」です。たとえば、ボタンは押せるままにして、未入力のまま押されたら案内を出し、最初の未入力の欄へ移動する。この動きをコードにすると次のようになります(HTML と JavaScript。このコードのまま Chromium 153 で、Tab キーでボタンを選べること、押すと案内が出てメールアドレスの欄へ移動すること、入力後に押すと「送信しています」と出ることを確かめました。未入力だけを確かめる短い例で、メールアドレスの形式の確認と、欄ごとのエラー表示(aria-invalid と aria-describedby)は省いています)。

<form id="contact-form" novalidate>
  <label for="email">メールアドレス(必須)</label>
  <input id="email" name="email" type="email" required>
  <button class="button" type="submit" aria-describedby="send-note">送信する</button>
  <p id="send-note">必須の項目を入力すると送信できます</p>
  <p id="form-status" role="status"></p>
</form>

<script>
  const form = document.getElementById("contact-form");
  const statusEl = document.getElementById("form-status");

  form.addEventListener("submit", (e) => {
    e.preventDefault();
    const firstEmpty = [...form.querySelectorAll("[required]")]
      .find((el) => !el.value.trim());
    if (firstEmpty) {
      statusEl.textContent = "必須の項目が入力されていません";
      firstEmpty.focus();
      return;
    }
    statusEl.textContent = "送信しています";
  });
</script>

フォーカスリングは CSS の :focus-visible に書きます。白い地の上に置くボタンの例です。暗い面や写真の上にも置くなら、内側に白い線を足すなど、2色の線にしておくと安心です。

.button {
  min-width: 10rem; /* 160px。読み込み中も幅を変えない */
}
.button:focus-visible {
  outline: 2px solid #111112; /* 白い地との差 3:1 以上 */
  outline-offset: 3px;
}

状態の仕様を短く書いて渡す

状態の一覧を Figma で並べたら、それとは別に、短い仕様を文字で書いて添えます。長い文書はいりません。部品ごとに、状態と「見た目」「動き」「伝え方」を並べるだけで、渡す相手が人でも AI でも、推測で埋める部分が減ります。Markdown(見出しや箇条書きを記号で書く書き方)で書いておけば、Figma の Specs にも、エンジニアのリポジトリの説明ファイルにも、AI への指示にも、そのまま貼れます。

## 送信ボタン(Button / Primary)

- 幅:最小 160px。読み込み中も幅を変えない
- hover:地を #2A2A2E に。パソコンだけ
- focus-visible:墨 #111112 の 2px の線、ボタンから 3px 外側。hover と別の見た目
- pressed:地を #3A3A3F に
- loading:文字を「送信中…」にし、左に回る印。role="status" に「送信しています」
- disabled:使わない。未入力のまま押されたら、エラーを出して最初の未入力の欄へ移動
- 例外:送信の二重押しを防ぐため、loading の間だけ押しても何もしない

## メールアドレスの入力欄(TextField)

- error:枠を赤 #D93025・2px にし、欄の下に印と文。文は「何が違うか」。書けるなら「どう直すか」も
- error の文は aria-describedby で欄と結ぶ
- 文の例:「@ のあとが入っていません。例:[email protected]」

コツは、数値と文言を具体的に書くことです。「分かりやすいフォーカス」ではなく「2px の線、3px 外側」と書いた部分ほど、実装でぶれません。

渡す前のチェックリスト

  • ボタンに、通常・ホバー・フォーカス・押している間の4つがある
  • フォーカスの印が、ホバーと違う見た目で、地の色と 3:1 以上の差がある
  • 送信・保存のボタンに読み込み中の状態があり、幅が変わらない
  • 読み込み中に、何をしているかが文字で分かる。読み上げる文も決めてある
  • 無効のボタンを使っていない。使うなら、理由と押せるようになる条件がすぐ近くにある
  • 入力欄のエラーが、色に加えて、印と文で伝わる
  • 状態ごとの数値(色、太さ、幅)と文言が、仕様の文に書いてある

全部を一度にそろえなくても大丈夫です。まずは送信ボタンとメールアドレスの入力欄の2つから、一覧と仕様を書いてみてください。

MODS BASE では、デザインシステムの整備や、デザインと実装をつなぐ進め方のご相談も受けています。チームでの決まりづくりに迷ったときは、お気軽にお声がけください。

( Written by )

MODS BASE

MODS BASEは、長野県上伊那郡辰野町を拠点に、WEB 制作、WEB 集客の運用代行、UI/UX デザイン・プロダクト開発、ブランディング・グラフィック、AI 導入支援を手がけるデザイン・開発スタジオです。全国のお客様にオンラインで対応しています。

( Related service )

WEB 制作

何を伝え、どう動いてもらうか。UX の設計から考えるホームページ制作。

( Related )

関連記事

( Contact )

Let’s talk.

まだ決まっていなくても大丈夫です。気になっていることから、気軽にお聞かせください。