ボタンなら、やるべきことはひとつだけ
(unsung.aresluna.org)- 写真の回転のような単純なボタンでも、高速な連続入力をどう処理するかによってユーザー体験は大きく変わる
- iPhoneは複数回押された90度回転の入力を記憶し、アニメーションが終わり次第、次の回転を続けて実行する
- Nothing Phone/Androidはハプティクスと音でタップを確認してくれるが、回転アニメーション中に入った後続のタップは無視する
- 文書写真を何枚も回転させる必要がある状況では、カジュアルな写真編集UIでも、より速く予測可能な操作が求められる
- ボタンはユーザーをアニメーション終了まで待たせるのではなく、タップのバッファリングやアニメーションの中断・加速によって入力を受け付けるべきである
写真回転ボタンが連続入力を処理する方法
- 写真回転ボタンは、1回押すと通常は反時計回りに90度回転し、もう一度押すと同じ動作を繰り返す標準的なコントロールである
- 回転アニメーションは、写真の向きが変わる過程を見せることで、ユーザーが方向感覚を失わないように助ける
- 90度回転を素早く8回押すと、エンジニアの言う「no op」のように、画像は2回転して元の向きに戻るはずである
- iPhoneでは、この期待どおりに実際に動作する
- 素早いタップ入力を記憶する
- 前の回転が終わると、待機中の次の回転を実行する
- Nothing Phone/Androidでは、異なる結果になる
- ボタンはハプティクスと音でタップ確認を提供する
- 前の回転アニメーションが終わっていなければ、新しいタップを無視する
カジュアルなUIでも、反復作業ではより強い入力処理が必要
- 状況的障害とは、障害は一部の人にだけ生じるものではなく、誰でも特定の状況では実質的に障害を経験しうるという概念である
- 写真撮影はたいていカジュアルな利用に近いが、スマートフォンのカメラは下向きに撮ると写真の向きを取り違えることがある
- 横向きの文書写真を何枚も撮ったあと、それぞれを回転しなければならないなら、ユーザーは写真を1枚ずつ数十枚回す必要があるかもしれない
- こうした状況では、ボタンを望む速度で3回押しても予測可能に動作するほうが、より快適で手間も少ない
- 十分に長い時間や大きなユーザー集団で見れば、カジュアルなインターフェースにも、より真剣に扱うべき瞬間が訪れる
- こうした「状況的パワーユーザー性」は、スマートフォンの写真編集やGarageBandのような事例でも現れる
- 解決策が必ずしもタップのバッファリングである必要はない
- 割り込み的なタップが入ったら、アニメーションを止めたり加速したりすることもできる
- 核心は、ユーザーにアニメーションの終了を待つことを強制しないことである
2件のコメント
Hacker News のコメント
ユーザーが誤ってクリックしすぎたり、最初のクリックが登録されなかったと思い込んだりした場合はどうすればよいのだろうか?
Steve Jobs が新しい macOS で PDF 文書の表示がどれだけ速くなったかを実演していた基調講演を今でも思い出す。エンジニアたちは PDF を画面上でスクロールするボタンを用意していたのだが、Jobs が誤って複数回押してしまい、「2回、最後までスクロールするのかな?」と言ったところ、実際に動作がバッファリングされた。結局、上に戻って、2回目のスクロールが終わるまで待たなければならなかった
Jobs は「2回目に文書をざっと見る時間まで含めても、以前の OS の PDF より速い」と言って取り繕った
デバウンスは理由があって存在する。ボタンを2回押したときに2回実行すべき場合もあれば、そうすべきでない場合もある。どの状況でどちらが望ましいかを見分けるのは簡単ではない
少なくとも、どの状況にどの処理が合っているのかを考える必要がある。UI の中には、あるボタンでは片方が明らかで、別のボタンではその逆が明らかなものもあるが、一部は曖昧で、どちらの動作も正当化できるなら、結局は一貫性のない UIになる
良い解決策はよく分からない
記事によると:
これが問題だ。アプリがボタン入力が登録されたと示した回数と、実際に実行された動作の数は同じであるべきだ。デバウンスは良い慣行だが、使うならデバウンスされたタップにはフィードバックを出してはいけない
「ユーザーが誤ってクリックしすぎたり、最初のクリックが登録されなかったと思い込んだりした場合は?」という部分でアクセシビリティの話が出てきて、かなり混乱した。すぐに、手の震えがある人が1回だけ押そうとして2回押してしまう場合が思い浮かんだからだ
それに、すべてのボタンをダブルクリックする人もいる。こうしたケースに対処するために、
onclickで送信ボタンを無効化するのは非常によくある昔のような Apple/Mac/Jobs のファンボーイではないが、すごいものを見せたい人が進行しているように見えたApple の発表が懐かしい
最近の Apple の発表はあまりに堅苦しく非人間的で、スーツ姿の人たちが運営している感じがして、最後まで見ることもできなかった。誰もが神聖な台本から外れたら解雇されるのではと恐れて、感情や人間味を隠すロボットのように見える
本題から外れているかもしれないが、Jobs の少々雑な即興プレゼンでさえ、どれほど楽しかったかを思い出す
「ではこういう場合は?」と言うには、この状況は明らかに違う。理由は2つある:
別のところで出ていた「デバウンスはどうなんだ?」という論点は支持したいし、筆者が単に無視すべきではない
しかし you had one job ミームも嫌いで、考えなしに使うことには反対したい。ほとんどの場合このミームは間違っており、ボタンについても概ね同じだ。一般的なユーザーインターフェースでは、特定のボタンは次の役割のうち複数を同時に担う:
ボタンに「仕事は1つ」という表現はあまり合っていない。ボタンはクリック可能であることだけでなく、複数の仕事をしなければならないからだ
クリックされたときのフィードバック、マウスを乗せたときのフィードバック、ローディング状態、無効状態、これらすべての組み合わせがある。これは非常にもどかしく感じられることもある。例えばバックエンドサービスに接続されたボタンを押すのに視覚的フィードバックが何もなければ、そのボタンが押されたのか分からない。ローディング状態もなければ、裏で何か処理中なのか分からず、何度も押し続けてしまう
筆者は、どんな速度で3回クリックしても常に同じ機能が実行されることを望んでいる。写真を素早くめくりながら、予測可能にそれぞれを回転させたいということで、それは妥当だ
筆者はアクセシビリティを根拠に挙げている
ただし、完全に反対側の主張も想像できる。たとえば運動障害やパーキンソン病のある人は、すでに意図が確定しているときには過剰なクリックが無視される動作を好むかもしれない
こういうものをきちんと作るのは難しい
iOSには Ignore Repeats というアクセシビリティオプションがあり、システム全体の設定なので、より良いアプローチに見える。こうした補正が必要な人は画面キーボードのような場所でも適用を受けられるし、それ以外の全員がタイピングを遅くする必要もない
すべてのUIウィジェットがこういうことまで考えるべきだとは思わない
デバイス全体の設定で処理できそうだ。たとえば、互いに50px以内にあるタップが100ms以内に繰り返されたら無視する、といった具合
完全に同意する。パーキンソン病までいかなくても、かなり高齢というほどではないが年配の人たちが携帯電話やタッチスクリーンを使う様子を見ると、小さなボタンを正確な位置で押して「自分は押した」という感覚を得るのが、しばしば難しいことが分かる
だからアクセシビリティの観点では、Nothing Phoneの動作のほうがずっと合っているように思う。そういうユーザーは、画像を特定の位置に置こうとして数を数えながら6回クリックしたりはしない。さらに、現在位置へ正確に戻るためにあらかじめ8回クリックするというのも、あまり筋が通らない
この場合の考え方は、「クリックして待ち、望む位置かどうかを比べ、もう一度クリックする」に近い。逆に入力をバッファリングする感度の高いボタンは、行き過ぎて、また戻りすぎるようなオーバーシュートを生みやすい。リストで目的の場所へスクロールしようとして、何度も外してしまう状況に似ている
iPhone方式は、待たずに素早く処理したい若い人や技術好きにより向いている。コンピューターのキーボードでも、遅延のせいで最初の文字が画面に表示される前に、複数の文字を先に入力できるのと同じ
以前、物理ボタン付きの機器を使ったことがある。押すとビープ音が鳴り、時間に30秒が追加されるボタンだった。ところが、あるときはビープ音は鳴るのに30秒が追加されず、別のときは音なしで30秒が追加された。なのでいつも暗い表示窓を目を細めて見ながら、動作したか確認しなければならなかった
これはひどく悪い設計だと思ったが、その後、純粋なソフトウェアボタンでも、この壊れた挙動をそのまま再現している例を数え切れないほど見た。画面上でボタンの色が変わることと、要求した動作が実際に実行されることが、ゆるくしか結び付いていない。なぜそんなことになるのか。いったいどう実装したらそうなるのか?
命令型コードを書いて2つの命令を出すが、そのどちらも独立して失敗し得る
これを「処理済み」と見なす方法はいくらでもある
まずテストは全部通るので、ほとんどの開発者はそこで考えるのをやめられる
例外を捕まえてログに残せばよいと考えることもできるが、それでは直らない
本番環境でしばらく動かして、問題が起きるかを見ることもできる。結局問題が起きれば開発者は再試行するだろうし、2回目はおそらく動くので、また考えるのをやめられる
数日前にはアウトボックスパターンについて大きな議論もあった。1つ目の仕事を2つの半分に分けてアトミックに処理し、2つ目の仕事は読者に任せる、というやり方だ
現実にこの問題が出続ける理由は、開発者たちが「そんなことは起きない」「自分が直した」「直せない」という量子重ね合わせ状態にいるからだと思う
ボタンの色を変えるコードは「ボタン」コンポーネントの内部動作なので、すべてのボタンごとに別々に実装しなくてもよい。しかしそれは、実際の動作を実行するコードとはある程度切り離されるという意味でもある。
on clickハンドラーに、元記事のように「回転アニメーション中なら画像を回転しない」といった最後のチェックがある場合、ボタンに色変更を取り消すよう知らせる方法がないことが多い。逆に、色変更アニメーションが正しく再生されなくても、on clickハンドラーは実行され得るボタンは通常、マウスボタンを押したときに色が変わるが、動作はマウスボタンを離したときに実行する。この方式は、押したままボタンの外へドラッグして最後の瞬間にキャンセルする機会を意図的に与えるものでもあり、モバイルではインタラクションをクリックではなくスクロールとして再解釈することもある。それ以外のときには、色がすでに変わった後で動作を止める機会を増やすだけになる
これは、現在のソフトウェア状態においてその押下が有用な入力かどうかとは完全に独立している。よく書かれたソフトウェアなら、入力を受け付けられないことを把握してボタンを無効化しているべきだし、そこそこよくできたソフトウェアでも、動作を処理中またはキャンセルされたというほぼ即時のフィードバックを提供すべきだ
人々は、アニメーションが純粋に補助的な役割であり、アニメーション自体が目的ではないという点をよく忘れる
アニメーションは読み込み時間を隠し、ある状態から別の状態へ滑らかに移行させるために存在する。だから使うのだ
この知識は結局失われ、今ではアニメーションが終わるまで待たなければならないコードが生まれている
驚くべきカーゴカルトのまた別の例だ
実のところ、「隠す」という表現には同意しない。何かがなぜ現れたのか手がかりもなく即座に表示されるのは、タッチスクリーンでは明らかなアンチパターンだ
昔のAppleは、デザインが見た目をきれいにすること以上のものだと理解していた。最近のガラス調のAppleは、デモでどう見えるかがすべてだ
最初の比較を見たとき、正直なところ問題は iPhone の例にあると思った。回転ボタンを押すたびに画像の下にあるボタンとスライダーが消えてから再びフェードインするが、これは iOS のいろいろなアプリで見た挙動で、延々と気に障る。特にスクリーンショットアプリには個人的に大きな不満がある
あるインタラクションの前後どちらでも操作できる UX 要素なら、変換であれ処理であれ、その間ずっと表示したままにすべきだ。iPhone で回転中にこれらのボタンを隠すことで、どんな UX 上の利点があるのか。見た目がよくなるわけでもない。もちろん最近の Apple ソフトウェアは、実際の UX 改善を見た目という祭壇に捧げてきたわけだが
ただし、こうしたタップはアニメーションとは独立して処理されるべきだという筆者の主張には同意する
UX にも似たものを作れるはずだ。よく知られた UX 上の欠陥がある状態でリリースしようとすると警告を出す、デザインパターン制約集のようなものだ
以前、赤ちゃんが使えるように作った BabyButton を実装したときのことを思い出した。通常のクリック動作の代わりに
touchdownイベントを使った。そうすると、子どもは何かが起きたことをすぐに見られるし、ボタンを長く押しすぎたり、押したまま指を動かしたりしても問題がなかったその年齢層向けのシステムを作るべきかどうかはまったく別の話だが、ユーザーの必要に合うものを設計するよい挑戦だったと感じた
現実のボタンは 99% 以上、押した瞬間に動作する。だが GUI でそのように動くボタンは奇妙に感じられるだろう
筆者が言おうとしている核心により近い本当の記事はこちら: https://aresluna.org/show-your-hands-honor/
通話中に iPhone の画面オン/オフボタンを押すと、あるときは通話が終了し、別のときは単に画面が消えるだけ、ということがあるのだろうか?
いまだにパターンが分からないが、iPhone をポケットに入れる前にそのボタンを押して、たまに誤って通話を切ってしまったことがある
Lobste.rsの反応
軽い皮肉ではあるが、良いUI/UXを語るなら、コントロールも表示もない動画埋め込みは最悪だと思う
自動再生をデフォルトでオフにしている人は多いし、ほとんど同じ画像を2枚見ながら「で、何が違うんだ?」としばらく考えていた
「アニメーションが終わるまでユーザーを絶対に待たせるな」には全面的に同意する
アプリなら、見た目の美しさよりもユーザーの操作が常に優先されるべきだ
この原則はゲームにも当てはまると思う。ゲームによっては、メニューを開いてから入力が受け付けられるまでごく短い遅延がある
派手なメニューアニメーションがあるゲームで、一時停止と下矢印キーを素早く押したとき、メニュー表示後に2番目の項目が選ばれているべきか、といった問題だ
ゲームにおける入力バッファリングは微妙なテーマだが、メニュー操作ではたいてい悪く感じられることは少ない
動画の情報の伝え方がよくなかった。ボタンを何度も連続して押す瞬間に気づくには、集中して見なければならなかった
本題に戻ると、Androidスマホが本当に間違っているのかも微妙だ。素早く8回押して望む結果を得たいもどかしさは理解できるが、デスクトップOSの誤ダブルクリック検知を思い出す
結局のところ、メーカーが考える使いやすさと、ユーザーが感じる利便性の差に近いように見える。あえて言えば、iPhoneがアニメーション中でも「Done」ボタンを表示する方が、むしろ気が散る感じがする
Androidが完全に間違っているとは言い切れない。反応の遅いUIのせいで動作を誤って2回実行したことがある
最善なのは、アニメーションが終わるまでボタンを無効化する方式かもしれない
「3回クリック」が通用せず、アニメーション中の追加クリックが無視される。クリックして画面を見ながらアニメーションが終わるのを待ち、またクリックしてまた待つ、という流れは遅いし、ユーザーの注意をかなり要求する
より良い解決策は、UIで即時フィードバックを出すことだと思う。クリックが処理されたことを示すボタン状態をすぐ描画したり、遅い全体アニメーションの前に一時的に素早く画面を再描画して現在の進行状況を見せたりできる
記事全体に強く同意する。これはアニメーションがヒポクラテスの誓いに反した問題だと表現したい
アニメーションの第一原則は「まず害をなすな」、つまり「まずユーザー入力を妨げるな」であるべきだ
ついてこられないロータリーエンコーダに遭遇したことはあるだろうか? 私のヘッドホンアンプの音量ノブは、速く回しすぎると何も起きない
一日だけ大統領になれるなら……
こういう話を見るたびに、自分のGUIツールキットならどうなるかを考える。自分のツールキットはWindowsプラットフォームから借りた挙動のように、素早い2回のクリックをダブルクリックとして扱うのだが、これがたまに本当に腹立たしい
ダブルクリック自体は一般的な慣習であり、クリックと区別される価値がある。理想的には、クリックイベントを冪等にして2回発生しても問題ないようにすべきだ。たとえばクリックが項目選択、ダブルクリックが既定の操作の実行なら、同じ項目を2回選択しても害はない。だが現実はいつもそうではない
問題は、ボタンをとても素早くクリックすると、ボタンは1回しか実行されず、その後はダブルクリックイベントに回って何もしないことがありうる点だ。つまり、速く押すとクリックの半分が無視される動作になる
この問題のために
triggersOnMultiClickというブール値を作り、trueに設定するとダブルクリックのような素早い複数クリックでもトリガーイベントを送出するようにした。ただ、後方互換性のためにデフォルトはfalseにしていたが、新しいメジャーリリースを出す時期になったので、記事の主張はもっともだと考え、デフォルトを今trueに変えようと思う「2021年7月2日追記、デフォルトは
false。2026年7月5日(v13.0)にデフォルトをtrueへ変更し、ボタンのすべてのクリックが標準でトリガーされるようにした。以前の挙動が必要ならダブルクリックイベントをオーバーライドするか、親コンストラクタ呼び出し後にtriggersOnMultiClick = falseを設定せよ」といった形で残せるアニメーション実装側でも、似たような挙動が偶然生じることがある。オブジェクト内にアニメーション位置変数を持ち、クリック時に値を設定するなら、ダブルクリック時の選択肢は大きく2つだ。残りのアニメーションを飛ばして次の内部状態へすぐ進むか、
if(animationCounter) return;のように視覚的な滑らかさを守るためイベントを無視するかだ。記事のAndroid開発者は後者を選んだように見えるApple側はおそらく3つ目の方式、つまり待機中のアニメーションキューを持ち、イベントをそこへ入れるやり方を使っているように思える。気になるのは、内部状態がキュー投入時に変わるのか、完了時点で変わるのか、それとも実際に画像をアニメーションで回転させているのかという点だ。途中でアニメーションを切って保存したら45度回転した画像になることもあるのだろうか? 自分ならEXIFを原子的に90度更新し、トランジションアニメーションは別で走らせると思う
実装の単純さ、視覚的忠実度、UIの挙動のあいだには、合理的な選択肢がいくつもありうる。個人的には、2回目の押下でアニメーションを待たずに新しい状態へ即座にスナップする方式も気に入る。アニメーションキューまでは作らないと思う
同じ時期にコードを変えるのはおもしろい。前回の修正も7月2日で、今回はたまたま7月5日だ。こういう履歴をドキュメントコメントにそのまま書いておくのが好きだ。後で変更するときに、思い出として読み返せるのもいい
Appleはたぶんデフォルトのアニメーションキューを提供していそうだが、状態変更のタイミングは依然として別問題だ。Webなら、状態を原子的に更新して、CSS
transformのトランジションのような視覚専用アニメーションを別に持つ気がする。レイアウト再計算も避けられるので、実装しやすく効率的そうだ。アニメーションより速くクラス名を切り替えたら、ジャンプするのかキューイングされるのかは、あとで試してみたい年を取ったせいか、誤ってダブルタップしたときに、こういう挙動にイラッとしたことが何度かある
同じ位置のボタンやダブルタップを確認手段にするのはひどい。本当に確認が必要なら、誤って確認が成立しやすい作りにしてはいけない
ただ、この例では素早い連続入力を受け付けるのは良い考えに思える。他のケースではそうでないかもしれない。物理ボタンの中には、何かが「終わる」まで2回押しを意図的に防ぐものもあり、常に意識的な設計とは限らなくても、時には正しい選択だ
カクつく機器や故障した機器を使わざるをえない人も多いし、手や指の震えのような健康上の問題があるなら、入力を制限することに利点があるかもしれない
この例は、どちらの立場にも理があるケースのように思える。待たされる方がずっと腹立たしい例もあるし、アニメーションであれ別条件であれ、入力制限があった方がよいと思える例も確かにある
モバイルブラウザの検索結果が指の下で更新され、自分が押そうとしていた選択肢を別の位置へ押しやるのは本当に絶えず腹立たしい
もっと待つよう自分を訓練してはいるが、UI操作が受信状態によって完了時刻がぶれるバックグラウンド非同期処理に左右されるべきだというのは、おかしい