押し込みの手応えトグル
「保存」「通知」「お気に入り」の 3 つのトグル。押している間だけ 0.96 倍に沈み、離すと弾んで戻る。切り替わった瞬間に navigator.vibrate があれば 10ms 震える。
プレビュー
クリック
操作クリック/タップで動きます。
仕様書
- 向く場面
- 保存・通知・お気に入りのような即時反映のトグル
- 押した手応えを返したいモバイルのボタン群
- 対応端末で短い振動を添えたい操作
- 避ける場面
- 送信で確定する設定(トグルは即時反映に見える)
- 縮小率を 0.9 倍以下にする
- 往復で弾ませる演出
- 構成要素
- トグルボタン
- アイコン(塗りで状態)
- ラベル
- 状態の案内文
- 持っている状態
- 通常
- フォーカス
- 押下中
- キーボード
Tab で各トグルへ、Space/Enter で切替。キー押下中も同じ沈み込みが出る
- 支援技術
aria-pressed で状態を伝え、色・アイコンの塗り・ラベル文言の 3 つで示す。結果は role=status で読み上げ。振動は navigator.vibrate 対応端末のみ
- 動き
押下 120ms で 0.96 倍に沈み、離すと 320ms のバウンス(1.04 倍まで 1 回)。切替時に 10ms 振動。reduced-motion で停止
デザインの要点
- 押下中の縮小は 0.96 倍まで。それ以上縮めると「壊れた」ように見え、色の変化と競合する
- 離したときの弾みは 1 回だけ。往復させると軽薄になる。cubic-bezier のオーバーシュートで十分
- 状態は aria-pressed に持ち、色・アイコンの塗り・ラベルの 3 つで伝える。色だけだと色覚特性で区別できない
- 振動は 10ms の短い 1 回。対応しない環境では何もしないので、機能の分岐は要らない
実装メモ
navigator.vibrate は Android Chrome 等で動き、iOS Safari では未定義です。未定義なら呼ばないだけなので機能分岐は不要です。押下中の縮小は :active でも書けますが、タッチでは :active の付き方がブラウザごとに揺れるため、pointerdown/up で明示的にクラスを付けています。
コード(コピーして使えます)
<div class="pst-card">
<p class="pst-head">この記事を</p>
<div class="pst-row">
<button class="pst-btn" type="button" aria-pressed="false" data-on="保存済み" data-off="保存">
<svg class="pst-ic" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h12v18l-6-4-6 4z"/></svg>
<span class="pst-label">保存</span>
</button>
<button class="pst-btn" type="button" aria-pressed="true" data-on="通知オン" data-off="通知">
<svg class="pst-ic" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 8a6 6 0 0 0-12 0c0 6-3 7-3 7h18s-3-1-3-7"/><path d="M13.5 21a2 2 0 0 1-3 0"/></svg>
<span class="pst-label">通知オン</span>
</button>
<button class="pst-btn" type="button" aria-pressed="false" data-on="お気に入り済み" data-off="お気に入り">
<svg class="pst-ic" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round" aria-hidden="true"><path d="M12 20.5 4.5 13a4.5 4.5 0 0 1 7.5-4.9A4.5 4.5 0 0 1 19.5 13z"/></svg>
<span class="pst-label">お気に入り</span>
</button>
</div>
<p class="pst-status" id="pst-status" role="status" aria-live="polite">通知をオンにしています</p>
</div>