ODD CODES 野地 剛のwebデザインとか音楽とか

jQueryでform部品にフォーカスを当てたままソフトウェアキーボードを閉じる小技


トップイメージ

トップイメージは我が家のキーボード君です。

それはさておき。

スマホやタブレットなどのタッチデバイスでform部品(inputやtextareaなど)にフォーカスが当たると出現するソフトウェアキーボード。

画面の半分、もしくはそれ以上の領域を占領するこのキーボードは他のコンテンツを見ようとするユーザーにとってイライラの原因となる。特に、入力を終えたユーザーにとってのキーボードは意味の無い、一刻も早く消してしまいたいものに違いない。

そこでユーザーは自然と画面の空白部分をタップするわけだが、ここで元々編集していた formからフォーカスが外れてしまう。

特にタッチデバイス向けのアプリなどを開発する際はタップ回数をいかに削減するかが一つのカギで、そのセクションに一つしか入力箇所がないのならば、ユーザーにいちいちフォーカスを当て直させるのは余計な手間である。

しかし、「ソフトウェアキーボードを閉じる条件=フォーカスを外す」となっている以上、フォーカスを当てたままキーボードを閉じるのは難しそうだ。しかも、「ソフトウェアキーボードが開く条件=フォーカスが当たる」なので、一瞬フォーカスを外してまたフォーカスしても再度キーボードが登場してしまう。

そこで今回の記事における主役の登場である。

今回の主役「readonry」属性

若干強引な手段ではあるが、今回の問題を解決してくれるのがinput要素などに設定できるreadonly属性だ。

これが設定されているform部品は読み取り専用になるため、ユーザーからの直接入力を受け付けなくなる(jsでvalue値をいじることは可能)。当然、読み取り専用ということでソフトウェアキーボードも表示されない。

ただし、同じような効果を持つdisabled属性と違い、このreadonly指定されたform部品はフォーカスの受け手となりうる。

つまり、フォーカスを受け取った状態で、すかさずこのreadonly属性を動的に指定してやればフォーカスを維持したままソフトウェアキーボードの出現を防ぐことが出来るのである。

実際のコード

jQuery使用前提なので注意。

//jQuery使用前提
$(function(){
    $('input').blur(function(){
        $(this).focus();
        $(this).attr('readonly',true);
        setTimeout(function(){
            $('input').attr('readonly',false);
        },10);
    });
});

ざっと解説

  1. 今回のターゲットであるinput要素からフォーカスが外れたのを検知(3行目)。
  2. 検知したと同時にフォーカスを当て直す(4行目)。
  3. フォーカスが当たったことで発生するキーボードの出現をreadonly属性を指定することで抑止(5行目)。
  4. setTimeoutにより、10mm秒後にreadonlyを外す(6、7行目)。

じっくり解説

input要素からフォーカスが外れたことを検知するblurイベントで作動する関数である。

まず、ユーザーが関係ないところをタップ(クリック)し、キーボードを消したはいいが、フォーカスが外れては困るのでfocus()で再度フォーカスを当ててやる。
ここでキーボードが再登場するのが悩みのタネであったわけだ。

そこで、すかさずattrメソッドでinput要素にreadonly属性を指定し、キーボードを無理やり退場させる。

ここで注意したいのが、attrの第二引数。普段、attr等で属性を指定するときは
.attr(‘id’,’hoge’);
のように指定するのだが、readonlyはオンオフで判断される属性なので第二引数に指定しうるのは true か false の二種類のみ。
しかも、’でくくってしまうと、JavaScript暗黙の了解により ‘false’=true というややこしいことになってしまうので、 true と false は何もくくらないで指定しよう。

さて、これで目標を達成したと思いきや、ここまでだと再度文字を入力しようとinput要素をタップしても二度とキーボードは現れない。readonly属性が指定されっぱなしになっているためなので、解除してやる必要がある。

そこで、setTimeout関数を使い、ごく短い時間(ここでは10mm秒後)の後にreadonly属性を解除。

これで、再度ユーザーがinput要素をタップしたときにキーボードが表示される(ちなみに、setTimeout関数を用いずに $(‘input’).attr(‘readonly’,false); と書くとその前に書いた $(‘this’).attr(‘readonly’,true); が完全に無かったことにされ、キーボードが出現してしまう)。

まとめ

なかなか強引な方法ではあるが、強引に出てくる相手には強引な手段で抑え込むのが一番である。多分。

ただ、この先タッチデバイスの普及、進化により新たなメソッドやらイベントやらが増えるのは確実だと思うので、その時はもっとスマートな方法が登場するだろう。
力技は個人的に大好きであるが、スマートに済むならスマートに済ませたいとろこである。