オリジナルのダイアログを閉じた時に、元の要素にフォーカスを戻す方法

先日、コーディングWebアクセシビリティ – WAI-ARIAで実現するマルチデバイス環境のWebアプリケーションという本を読みました。Webアクセシビリティについて書かれた実践的な本で、WAI-ARIAについて全くと言っていいほど知らなかった自分には、もっと入門的な本も必要だと思いました(本の内容が難しいとうわけではありません。書いてあることは易しかったのですが、自分はこの本の想定読者のレベルに達してないというだけです)。ただ、この本を読んでもっとWebアクセシビリティを意識したサイトを作っていこうと思えたので、そういう意味では読んでよかったと思います。

さて、本を読み終わったらいつもブクログに本の感想というか批評というか日記というか、とにかくその本について思ったことを書くのですが、なんと今回はそのレビューページを、この本の編集の方に見てもらえたらしく、さらにレビューに書いた疑問を監訳者の方にまで見てもらえたようです(『コーディングWebアクセシビリティ – WAI-ARIAで実現するマルチデバイス環境のWebアプリケーション』のレビュー ヘイドン・ピカリング (amano225さん) – ブクログ)。たまにこうやって関係者からのコメントをもらえることがあるのですが、見られることを想定して書いてるわけではないので、嬉しくもありますが、どこか恥ずかしい気もちもあり、複雑なところです(さすがにオープンな場に書いている以上、見られたくないとは思っていません)。

ところで、自分が疑問に思ったのは本書の最後にほうに書いてあるダイアログについての記述です。ダイアログを閉じる時に、そのダイアログを開く前にフォーカスのあった要素にフォーカスを戻しましょうと書かれてあったのですが、それがあまりにも冗長のように思いました。本書には下記のように書いてありました。

ダイアログを開く時の処理

var trigger = $(this).attr('id') ? $(this).attr('id') : 'origin';

ダイアログを閉じる時の処理

$('#' + trigger).focus();

つまり、開いた時にフォーカスがある要素のIDを取得し、なければその要素に’origin’というIDをつける(IDをつける処理は省略)。そして、閉じる時にそのIDから要素を選択して、その要素をフォーカスするという記述です。

なんだか冗長です。自分は下記のようにしたほうがいいのではないかとブクログに書いた次第です。

ダイアログを開く時の処理

var $trigger = $(this);

ダイアログを閉じる時の処理

$trigger.focus();

編集の方によると、確かにこちらのほうがいいだろうとのことでした。自分の意見が認められたみたいでうれしいです(意見したつもりはないのですが)。

さて、ここまでは余談です。今回、実際に作ってみることにしました。まず、HTML内にダイアログ用の記述として下記のような記述を追加します。

<div class="dialog dialog--hide" id="TestDialog" role="alertdialog">
    <div class="dialog__layer"></div>
    <div class="dialog__box">
        <p class="dialog__box__message">正しい書式で入力してください</p>
        <div class="dialog__box__btnDiv"><input type="button" value="OK" class="ok-btn"></div>
    </div>
</div>

.dialog__layerはレイヤー用ですが、#TestDialogの背景をrgbaで指定しても同じことになるので、必要ないかもしれません。

CSSは下記のようにしました。クラスの命名は最近話題のBEMっぽくしてみました(参考:BEMを参考にしたCSS設計 – Qiita)。

.dialog{
    position:fixed;
    top:0;
    left:0;
    width:100%;
    height:100%;
    z-index: 100;
}
.dialog--hide{
    display: none;
}
.dialog__layer{
    position: absolute;
    top: 0;
    left: 0;
    width:100%;
    height:100%;
    background-color:gray;
    opacity: 0.7;
}
.dialog__box__message{
    font-size:25px;
    padding:15px;
}
.dialog__box{
    background-color: #fff;
    position: absolute;
    top: 0;
    left: 0;
    right:0;
    bottom:0;
    margin:auto;
    width:500px;
    height:200px;
}
.dialog__box__btnDiv{
    text-align: center;
    position:absolute;
    bottom:0;
    left:0;
    width:100%;
    padding:10px;
}
.dialog__box__btnDiv input{
    font-size:20px;
    padding:5px;
    min-width:100px;
}

次にJavaScriptの記述です。

$(function(){
    var $dialog = $('#TestDialog');
    // ダイアログを開く関数
    var openDialog = function(msg){
        $dialog.find('.dialog__box__message').html(msg);
        $dialog.removeClass('dialog--hide');
        // 現在のフォーカスを取得
        var current_focus = document.activeElement;
        $dialog.data('back-focus', current_focus);
        $dialog.find('.ok-btn').focus();
    }
    // ダイアログのOKボタンを押した時の処理
    $dialog.find('.ok-btn').click(function(e){
        $dialog.addClass('dialog--hide');
        // フォーカスを戻す処理
        var next_focus = $dialog.data('back-focus');
        $(next_focus).focus();
    })
});

何をしているかというと、ダイアログを開いた時にdocument.activeElementで現在フォーカスしている要素を取得しています(参考:JavaScriptでフォーカスのあたっている要素を取得する「document.activeElement」: 小粋空間)。そして、その要素をjQueryのdataメソッドでダイアログ用のタグに”back-focus”というキーで紐付け、ダイアログ内のボタンをおした時にその要素を取得してフォーカスを元に戻すという処理を行っています。

試しに、テキストボックス内に郵便番号を入力してエンターキーを押すと、書式が正しくなければ”正しい書式で入力してください”、正しければ”OKです”と表示するサンプルを作成してみました。
実行サンプル:ダイアログのテスト

エンターキーを押したらダイアログがでて、そのままエンターキーを押したらフォーカスが元に戻るのが分かると思います。注意点として、エンターキーをおした時にダイアログを表示する場合は、下記のようにe.preventDefault()がないとすぐに閉じてしまうようです。

// テキストボックスフォーカス中にエンターキー押下
$('#zip-code').keydown(function(e){
    if(e.keyCode === 13){
        e.preventDefault(); // この指定がないと、ダイアログのOKボタンまで押してしまう
        var str = $(this).val();
        var reg = new RegExp($(this).attr('pattern'));
        var msg = '正しい書式で入力してください';
        // 指定のパターンの時
        if(str.match(reg)){
            msg = 'OKです';
        }

        openDialog(msg); // ダイアログ表示
    }
});

特にこだわりがなければ、alertメソッドを使えばいいだけの話なんですけどね。ダイアログのレイアウトも変更したいという場合に。

ところで、document.activeElementという指定はつい最近知ったのですが、調べてみるとIE4の時からあった指定方法だそうです(document.activeElement – Web API インターフェイス | MDN)。昔からある手法ななのに、初めて知ることがあると、自分はまだまだ全然JavaScriptを分かってないんだなと思います。

コメント

タイトルとURLをコピーしました