2022.02.08

モーダル表示時にフォーカスをモーダル内で循環させる方法|ウェブアクセシビリティ対応

こんにちは、webエンジニアのゾノ( @ozonosho )です。

今回は記事ではモーダル表示時にフォーカスをモーダル内で循環させる方法をご紹介いたします。

キーボード操作でサイトを閲覧する方はタブキーを利用してコンテンツを読み進めていくため、サイト制作者は各要素のtabindexを適切に制御する必要があります。

モーダル表示時には、モーダル内の要素だけでフォーカスが循環するように制御します。そうしないとタブキーでフォーカス遷移した際に背面に隠れている要素にフォーカスが当たってしまうためです。

同様に、よくあるスマホのドロワー型ナビにおいても、ドロワーがオープン状態のときにはドロワー内の要素だけでフォーカスが循環するように制御する必要があります。

ウェブアクセシビリティの観点でいえば「フォーカス順序の制御」は適合レベル「A」を満たすために必須の対応となります。

※詳細はこちら
『フォーカス順序:達成基準 2.4.3 を理解する』

モーダル表示時にフォーカスをモーダル内で循環させる方法

よくありそうなモーダル表示のHTMLを用意してみました。

<div id="modal-area">
	<button type="button" class="modal-btn">開く</button>
	<div class="modal-content">
		<ul>
			<li>
				<a href="">リンクA</a>
			</li>
			<li>
				<a href="">リンクB</a>
			</li>
			<li>
				<a href="">リンクC</a>
			</li>
		</ul>
	</div>
</div>

modal-btnをクリックするとmodal-contentがポップアップでモーダル表示されるものとします。

スマホのドロワー型ナビでもイメージしやすいようにモーダル内にはaタグをいくつか入れてみました。

この場合、モーダル表示時のフォーカス遷移は「開く」「リンクA」「リンクB」「リンクC」だけで巡回するよう制御する必要があります。

※フォーカス順序とは別のウェブアクセシビリティ対応として「モーダル表示時は開くボタンの文言を閉じるに変更する」「aria-expanded属性等を利用して開閉状態を伝える」という対応も必要になりますがここでは割愛します

実際にフォーカス遷移を制御するためのコードが下記になります。

$(function(){
    //フォーカスを当てたい要素を取得
    var modalElements = $('#modal-area').find('a, button');
    //開閉状態を取得
    var isOpenDrawer = false;
    $('.modal-btn').on('click', function () {
        $(this).toggleClass('open');
        if($(this).hasClass('open')) {
            isOpenDrawer = true;
        } else {
            isOpenDrawer = false;
        }
    });
    //モーダル表示時はフォーカスをモーダル内で循環させる
    $(document).keydown(function(event) {
        if(isOpenDrawer) {
            //フォーカスが当たっている要素
            var activeEl = document.activeElement;
            //モーダル内でフォーカスを当てたい最初の要素
            var firstEl = drawerElements[0];
            //モーダル内でフォーカスを当てたい最後の要素
            var lastEl = drawerElements[drawerElements.length - 1];
            //タブキーを押されたかどうか
            var tabKey = (9 === event.keyCode);
            //シフトキーが押されたかどうか
            var shiftKey = event.shiftKey;
            //最後の要素でタブキーが押された場合、最初の要素にフォーカスを当てる
            if(!shiftKey && tabKey && lastEl === activeEl) {
                event.preventDefault();
                firstEl.focus();
            }
            //最初の要素でタブキー+シフトキーが押された場合、最後の要素にフォーカスを当てる
            if(shiftKey && tabKey && firstEl === activeEl) {
                event.preventDefault();
                lastEl.focus();
            }
        }
    });
});

キーボード操作の場合、タブキーで次の要素に進み、タブキー+シフトキーで前の要素に進むため、それぞれの場合でフォーカスがモーダル内の要素から外れないように制御します。

これでモーダル表示時やドロワー表示時にその中の要素だけでフォーカスが循環するようになります。

おわりに

以上、今回の記事ではモーダル表示時にフォーカスをモーダル内で循環させる方法を紹介させていただきました。