ページ本文へ移動
SUMIBIBLOG
ねこ ねこ

JS不要でアクセシビリティ配慮のHTML/CSSスライドメニュー

ブラウザをキーボードで操作する場合にメニューの開閉ボタンはフォーカスできるよう<button>要素を使います。かつては<button>要素を操作するためにJavaScriptを使っていましたが、現在ではHTMLとCSSのみで操作ができるように対応が進んでいます。

そこで実際にJavaScriptを使わずにアクセシビリティに配慮したスライド形式のメニューを作成しようと思います。

目次

Invoker Commands API

「Invoker Commands API」が主なブラウザに実装され 、ボタンに動作を割り当てる方法を提供しています。スペースバーやリターンキーなどのキー操作やマウスクリックでボタンが有効になると、特定の要素を制御できます。今回のメニュー表示では開くための<button>を操作すると<dialog>にopen属性が付与され、閉じるための<button>はopen属性を消します。

Closedbyの対応状況

Invoker Commands APIを操作できる属性の「command」と「commandfor」を<button>に付けると共に、<dialog>に「closedby」を付与すると<dialog>を閉じるのに<button>以外の操作を加えられます。メニュー領域以外のクリックやエスケープキーの操作で<dialog>のopen属性を取り除きます。

ただし「closedby」は2026年6月現在では主なブラウザの内、Safariでは動作しません。2026年4月にSafari Technology Preview 242に含まれたので、しばらく待てば使えるようになるでしょう。「closedby」が動かないブラウザのためにJavaScriptで補えば、現状でも「Invoker Commands APIと「closedby」を使いアクセシビリティを考慮したメニューをサイトに実装できます。

基本のHTML構造

HTMLは基本的に以下のように記述します。

<button type="button" commandfor="d1" command="show-modal" aria-label="メニューを開く">
    <svg aria-hidden="true"></svg>
</button>
<dialog id="d1" closedby="any" aria-labelledby="d3">
    <h2 id="d3">メニュー</h2>
    <nav>
        <ul>
            <li><a autofocus href="#">リンク1</a></li>
            <li><a href="#">リンク2</a></li>
            <li><a href="#">リンク3</a></li>
        </ul>
    </nav>
    <button type="button" commandfor="d1" command="close" aria-label="メニューを閉じる">
        <svg aria-hidden="true"></svg>
    </button>
</dialog>

<button>には必ず「type="button"」を付けます。「commandfor」で操作する<dialog>のidを指定し「command」で操作の内容を表します。<dialog>に「closedby」で「any」「closerequest」「none」のいずれかの値を指定することで閉じ方を選べます。

visibility: hiddenで要素を隠す場合

画面外のメニューがボタンの操作で画面内にスライドして表示させる場合のCSSについて考えます。キーボードでブラウザを操作する場合やスクリーンリーダーで読み上げる場合に画面外にあるメニューを無視するために「visibility: hidden」か「display: none」を使います。

「visibility: hidden」は要素は存在するけど中身は見えない状態で「display: none」は要素自体が存在しないという違いがあります。スライドをアニメーションで表現するには「visibility: hidden」が簡単です。要素が存在しているので「hidden」と「visible」を切り替えるだけです。以下のCSSで動作します。

dialog {
    display: block;
    visibility: hidden;
    transition: .5s ease-out;
    right: -300px
}
dialog[open] {
    visibility: visible;
    right: 0
}

dialogにdisplay:blockをあえて書いているのはFirefoxで閉じる際のアニメーションを表示させるためです。display:blockがない場合はボタンの操作と同時にメニューが消えます。Chromeは書かなくても問題ないのでFirefoxのバグかもしれません。

「visibility: hidden」ではメニューの表示時に「autofocus」属性を付与されたリンクがフォーカスされません。仕様ではメニューが表示されると「autofocus」が存在するリンクがフォーカスされ、「autofocus」が無い場合は<dialog>にフォーカスするとなっていますが、「autofocus」が存在しても<dialog>にフォーカスします。

試しにtransitionの時間を0にすると「autofocus」があるリンクにフォーカスし、仕様のように動作しました。レンダリングの関係で時間が掛かるとうまくいかないようです。解決方法はJavaScriptでフォーカスをコントロールするしかなさそうです。

display: noneを使う場合

一方「display: none」を使えばアニメーションの時間があっても「autofocus」のあるリンクにフォーカスします。ただ、「display: none」から「display:block」へのアニメーションのCSSは記述量が増えます。以前は不可能だったのですが「@starting-style」でdisplay:noneの状態でのプロパティを定義し、「allow-discrete」でアニメーションの時間の間に値が変更しないようにできるようになりました。

今回の場合だとボタン操作から0.5秒間経ってから「display:none」になるように指定しているのが以下のCSSです。

dialog {
    display: none;
    right: -300px;
    transition: right 0.5s ease-out, display 0.5s allow-discrete, overlay 0.5s allow-discrete
}
dialog[open] {
    display: block;
    right: 0
}
dialog::backdrop {
    opacity: 0;
    transition: opacity 0.5s, display 0.5s allow-discrete, overlay 0.5s allow-discrete
}
dialog[open]::backdrop {
    opacity: 1
}
@starting-style {
    dialog[open] {
        right: -300px
    }
    dialog[open]::backdrop {
        opacity: 0
    }
}

transitionのoverlay 0.5s allow-discreteはdialog::backdropが消えるときのアニメーションに必要です。dialog,dialog::backdropの両方にoverlay .5s allow-discreteを記述すると初めてdialog::backdropが0.5秒かけて消えるようになります。

Can I Useで「allow-discrete」を調べるとFirefoxも対応していると表示されますが、実際は動作していません。バグとして認識されているようなので修正を待っていますがなかなか修正されず、メニューが消える際のアニメーションが動作しません。

最後までお読みいただき、誠にありがとうございます。

10%OFF
モダンHTML&CSS 現場の新標準ガイ…
モダンHTML&CSS 現場の新標準ガイド
エビスコム 著
Amazon.co.jp
自作テーマ

自作テーマのランキング

1
Amazon PA APIからCreators APIへ移行|Offers V1終了の対策と方法
Amazon Creators API
2
Amazon PAAPI廃止とCreators API完全移行への対策|5月15日
PAAPI 5.0 Deprecation
3
SEOプラグイン不要!WordPress構造化データ自作手順
Structured Data Jason-ld WordPress
4
iframeからHTMLへ・Turnstileで強化する問い合わせフォーム
Cloudflare Turnstile Contact Form
5
WordPressでClarity APIを使った人気記事ランキング作成方法
Microsoft Clarity access ranking

総合ランキング

1
U字溝と耐火レンガで作る格安の焼鳥台の作り方と使い方
U字溝と耐火レンガで炭火を使う
2
鉄久で焼鳥を焼く・焼鳥台の工夫と鉄の棒の購入と使い方
U字溝と鉄久
3
キャビティプロ導入で水槽管理はどう変わる?3ヶ月使用レポート
キャビティプロ
4
低価格で高音質!中華アンプとDACのASRの評価とその選び方
Fosi Audio V3
5
Volumio OSで高音質再生!PCに導入から設定まで完全解説
Volmio
管理者
ほんだ

当サイトの管理者 : 炭火で美味しいものを作ることを中心に、日々の趣味についてを文章にすることで、WordPressを使ってのWebページ作成を忘れないようにするブログです。熱帯魚の世話や野菜の栽培、Linuxについて、音楽を聴くための機材やアイデアなど、興味のあることを書いています。兵庫県在住。