2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JavaScriptにおけるDOM構造操作とアクセシビリティ:動的要素と構文的責任の分離戦略

Posted at

概要

DOM操作はUIを構築する力であると同時に、アクセシビリティ(a11y)を破壊する力でもある。
見た目だけでなく、構造的意味・操作性・ナビゲーション可能性を保ったままDOMを動的に変更することが、モダンなJavaScript UI設計には求められる。

本稿では以下の観点で整理する:

  • 意味論的HTMLとDOM操作の整合
  • aria属性の設計と状態管理
  • フォーカス管理とキーボードナビゲーション
  • UI状態とDOM属性の同期
  • ライブリージョンによる動的通知

1. 意味論的HTML(semantic HTML)との協調

divベースの構造操作

const el = document.createElement('div');
el.innerText = 'Click me';
el.addEventListener('click', handleClick);

→ 非セマンティック、スクリーンリーダー未対応


✅ HTML5タグ + 明示的な属性

const button = document.createElement('button');
button.innerText = '削除';
button.setAttribute('aria-label', 'この項目を削除');
  • button, nav, section, dialog などのHTMLタグを優先
  • ✅ アクション要素は role="button" ではなく<button>

2. aria属性と状態同期

const menu = document.getElementById('menu');
menu.setAttribute('aria-expanded', 'false');

function toggleMenu() {
  const expanded = menu.getAttribute('aria-expanded') === 'true';
  menu.setAttribute('aria-expanded', String(!expanded));
}
  • ✅ 状態変更時に aria-*明示的に同期
  • aria-expanded, aria-hidden, aria-pressed など状態を語る属性を積極的に使う

3. フォーカス管理:動的要素とアクセシビリティの両立

const modal = document.getElementById('dialog');
modal.showModal();
modal.querySelector('button.close').focus(); // フォーカスを送る
  • ✅ ダイアログ表示時は初期フォーカスを明示的に設定
  • tabindex="-1" を使ってJSからフォーカス可能にするのが定石

4. キーボードナビゲーション設計

element.addEventListener('keydown', (e) => {
  if (e.key === 'Escape') {
    closeDialog();
  }
});
  • ✅ Escape → ダイアログ閉じる
  • ✅ Enter/Space → ボタンを発火
  • ✅ 矢印キー → リストナビゲーション etc.

→ キーボード操作が全UIと等価であることが重要


5. aria-live:動的更新の通知

<div id="announce" aria-live="polite" class="sr-only"></div>
announce.textContent = '保存に成功しました';
  • ✅ ユーザーに見えないがスクリーンリーダーには通知される
  • aria-live="polite"(非強制) / assertive(即時)

6. UI状態とDOM構造の同期責任

function toggleSection(section, isOpen) {
  section.setAttribute('aria-hidden', String(!isOpen));
  section.classList.toggle('hidden', !isOpen);
}

→ ✅ 視覚的状態(class)と意味的状態(aria)を同期させる


7. モジュールとしての責任分離

  • dom/createButton.js → ボタン生成
  • a11y/setAriaExpanded.js → ARIA属性の更新
  • focus/trapFocus.js → モーダル内でのタブ移動制御

→ ✅ 各ファイルが1つの意味的責務を担い、明示的な設計となる


設計判断フロー

① 操作対象は何か? → ボタン・入力など意味のあるHTMLタグを使う

② 状態がある? → aria属性で状態を表現(expanded, pressed)

③ 動的UI? → DOM更新に合わせてARIAやフォーカスも更新

④ 通知が必要? → aria-liveで視覚外の情報を伝える

⑤ キーボード操作に対応しているか? → keydown/keyupで補完

よくあるミスと対策

<div>をボタン代わりにクリックイベント

→ ✅ buttonタグで、アクセシビリティと自動フォーカスを確保


❌ 状態だけclassで制御、aria未設定

→ ✅ classとariaを並行管理する


❌ ダイアログやモーダルにフォーカスが移らない

→ ✅ focus()tabindex="-1" を組み合わせて制御


結語

DOM操作とは、UIの見た目を変える技術ではない。
それはユーザーがどう見るか、どう理解するか、どう操作するかを構造として設計する技術である。

  • 意味を持つHTMLを選び
  • 状態を属性で語り
  • 操作をキーボードと同期し
  • 表示されない情報も伝える

アクセシブルなDOM操作は、すべてのユーザーに届く設計である。
その設計は、構文・視覚・操作性の三位一体で成立する。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?