detailsタグとsummaryタグを使ったアコーディオンをアニメーションさせようとしたらつまづいた
公開日:
タグ:
- #アクセシビリティ
details 要素と summary要素は他の要素を使用して実装するよりもアクセシビリティ面で最適化されるため、積極的に使っていきたいです。
メリット
- マークアップだけで開閉する機能が実装できる
- アクセシビリティ対策を全て対応してくれる
- タブキーでフォーカス、エンターキー、スペースキーでの開閉の操作を全て対応してくれる
- スクリーンリーダーでの読み上げ時に、開閉状態を適切に読み上げてくれる
- ページ内検索で隠れているコンテンツも検索の対象になる
ただ、よくあるアコーディオンのようなアニメーションをつけようとなった場合、各ブラウザでの対応を考えるとJavaScriptで実装しなくてはならない部分があります。それでも上記のメリットを実装の考慮に入れずに済む点でも使うメリットは大きいと考えています。
今回つまづいたポイント
details 要素はsummary要素をクリックした際にopen属性が付与・削除されます。それに合わせて開閉がされます。
open属性はtrue または falseで開閉を判定しているのではなく、単純にopen属性を付与・削除で判定される点には注意が必要です。
今回はそこを理解しておらず、true・falseで実装したため、常に開いた状態と判断され、閉じている時にも中の要素にフォーカスが当たったり、スクリーンリーダーで読まれたりする状態になってしまいました。
this.isOpen には現在の開閉の状態がboolean型で入る想定で考えた時、正しく実装する際は removeAttributeを使用して open属性を削除してください。
// NG
this.details.setAttribute('open', this.isOpen)
// OK
this.isOpen ? this.details.setAttribute('open', '') : this.details.removeAttribute('open')
ちなみに今回、 open 属性の付与のタイミングは transitionend イベントでを使用して details 要素ないのアニメーションが完了したタイミングで付与することで、連続でクリックした際の実装を省略しました。今のところこれが良さそうだと思ってますが、もし何か他にいい実装があれば教えていただけるとありがたいです。
以下、デモを作ったので確認してみてください!
こぼれ話
HTMLDetailsElement: open プロパティ - Web API | MDN には
この論理値は HTML の
open属性の状態を表します。trueの値は、概要と追加情報の両方がユーザーに示されている状態で設定されていることを意味します。falseの値は設定されていないことを意味し、概要のみが表示されます。
と書かれていたのですが、
<details>: 詳細折りたたみ要素 - HTML | MDNには
詳細を非表示にするには、この属性を完全に削除する必要があります。この属性は論理属性なので、
open="false"では詳細が表示状態になります。
とはっきり書かれていたので自分の確認不足でした…ドキュメントちゃんと読みましょう。
それから、最近Macが新しくなったのでSafari、Firefoxでタブでのフォーカス設定がデフォルトのままだったので混乱してしまったのも原因でした。
Safariでは設定>詳細>アクセシビリの中の「Tabキーを押した時にWebページ上の各項目を強調表示する」にチェックを入れておかないと、リンクなどにはフォーカスが当たらないのでチェックを入れておいた方が良さそうです。

チェックを外してる場合は、テキストフィールとポップオーバーにだけ強調表示が入るそうで、details要素がポップオーバーとして認識されていたため強調表示の挙動の違いに気づかないままでいました。
何かおかしいと思ったらデフォルトの設定も見直してみてください。