見出し画像

[JavaScript] aria-expanded 属性で要素を開閉する機能を実装

ナビゲーションのサブメニュー開閉用にキーボードでも操作しやすいボタンを付ける。

身体的にマウス操作の苦手な人もいる。そういう方へ情報発信するサイトなら、サブメニューの開閉に一般的なマウスオーバー以外の機能も必要。
HTML の aria-expanded 属性と CSS で要素を開閉表示する。

結果は『まとめ』の CodePen で。

[JavaScript]

function ToggleAriaExpanded( el ) {
	if ( 'true' !== el.getAttribute( 'aria-expanded' ) ) {
		el.setAttribute( 'aria-expanded', 'true' );
	} else {
		el.setAttribute( 'aria-expanded', 'false' );
	}
}

クリックしたボタンの aria-expanded 属性の値を切り替えるスクリプト。

[HTML]

<ul>
	<li><a href="#">Parent</a>
		<button class="sub-menu-toggle" aria-expanded="false" onclick="SubMenuAriaExpand(this)">
    	<span class="open" title="Sub menu open">+</span>
    	<span class="close" title="Sub menu close">-</span>
		</button>
		<ul class="sub-menu">
			<li><a href="#">Child</a></li>
		</ul>
	</li>
</ul>

aria-expanded="false"
最初は閉じているので false。開くときはスクリプトで true に切り替える。
aria-expanded はボタンなどのコントローラ側の属性。開閉される側ではない。

onclick="ToggleAriaExpanded(this)"
ボタンクリックでスクリプトを実行する。


細かいことをいうと開閉される側の aria-hidden 属性や、コントロール対象を関連付ける aria-controls 属性などが存在するが、今回は操作上必須の箇所だけ対応。


[CSS]

[aria-expanded="false"] + .sub-menu {
  display: none;
}

[aria-expanded="false"] > .close {
  display: none;
}

[aria-expanded="true"] > .open {
  display: none;
}

ボタンに隣接する .sub-menu の display プロパティを操作して開閉させる。
ボタンも「開く/閉じる」の表示を切り替える。

javascript でスタイルも変更できるが、「ボタンクリックで HTML のコードが変わる」ことと「属性に合わせて見た目が変わる」ことは分けて書いた方が管理しやすい。
CSS を別のモジュールで一元管理している場合もあるし、デザイナーとコーダーが別の場合も領域を分けたほうが作業しやすい。

ナビゲーションが複数ある場合

サブメニューが増えると開きっぱなしは不便かも。
グループ内で同時に開くサブメニューをひとつに制限する。

[JavaScript]

function SubMenuAriaExpand( el ) {
	el.closest( 'nav' ).querySelectorAll( '.sub-menu-toggle' ).forEach( function( button ) {
		if ( button !== el ) {
			button.setAttribute( 'aria-expanded', 'false' );
		}
	} );
  
  ToggleAriaExpanded( el );
}

el.closest( 'nav' )
指定の要素の親要素を探す。
要素名、クラス名(.class)、ID(#id) などグループ化に使っている名称を指定可能。
今回は el(クリックしたボタン)の親要素(nav)を探す。

querySelectorAll( '.sub-menu-toggle' )
クラス名 sub-menu-toggle の要素を検索する。
検索範囲はさっき closest で指定した nav の中。

forEach( function( button ){ ... } )
querySelectorAll と合わせて、見つかった要素を1個ずつ処理する。
今回はボタンの aria-expanded を false にすることで、一旦すべてのサブメニューを閉じている。

ToggleAriaExpanded( el );
最初に書いた切り替えスクリプトを呼び出し、クリックしたボタンのサブメニューは開く。

[HTML]

<button class="sub-menu-toggle" aria-expanded="false" onclick="SubMenuAriaExpand(this)">

onclick="SubMenuAriaExpand(this)"
ボタンのクリックアクションを追加したスクリプトに変更する。

まとめ

ボタンを1個ずつ付けるのは大変かもしれないが、今時ならスクリプトやCMS系のテンプレートでほぼ自動入力が主流だと思うのでこれで…。

参考リンク

aria-expanded - WAI-ARIA - W3C
Element: closest() メソッド - Web API | MDN
Element: querySelectorAll() メソッド - Web API | MDN
NodeList: forEach() メソッド - Web API | MDN


この記事が気に入ったらサポートをしてみませんか?