フラグメント(DocumentFragment)での効率的な操作
概要
DocumentFragment は、実 DOM ツリー(画面に描画される DOM)とは切り離された、軽量なコンテナノード(nodeType === 11)です。
フラグメントの中で要素をまとめて組み立て、最後に親要素へ 一度に挿入 することで、レイアウト計算・再描画・スタイル計算(いわゆる reflow / repaint)を最小化 できます。
挿入時には「フラグメント自身」ではなく「その子要素たち」が親に移動するため、フラグメントは自動的に空 になります(使い捨ての作業台のイメージ)。
なぜ効率的か(パフォーマンスの要点)
-
バッチ挿入:大量のノードを1回の DOM 操作で投入できるため、逐次挿入に比べてレイアウトやスタイル計算の発生回数が減ります。
-
オフドキュメント作業:画面外(未接続)でノードを組み立てるため、その間はレイアウトが発生しません。
-
移動が安い:フラグメントを挿入すると、子ノードが**移動(adopt)**されるだけでコピーされないためコストが低い。
基本 API と挙動
-
appendChild(frag)やappend(frag)を呼ぶと、frag の子だけが親に挿入され、fragは空になります。 -
querySelector/querySelectorAllはDocumentFragmentでも使用可能です。 -
ノードを移動する挙動なので、既存ノードに付けたイベントリスナやプロパティは保持されます(新規に HTML 文字列から作ったノードには、当然リスナは付いていません)。
代表的な使い方
1) 大量要素の一括追加
2) 既存ノードの再配置/並べ替え
3) HTML 文字列 → フラグメント化して安全に挿入
Range#createContextualFragment を使うと、コンテキストに沿ったパースを行い、結果を DocumentFragment として得られます。
※ innerHTML と同様に HTML をパースしますが、createContextualFragment は DOM ノードとして直接受け取れるため、挿入前にフラグメント内で検査・加工しやすい利点があります。挿入済みの <script> は通常自動実行されません。
4) <template> 要素と組み合わせる
<template> 要素と組み合わせる<template> の content は DocumentFragment です。複製してから中身を書き換え、一括挿入できます。
5) 置換系 API との併用(全入れ替えを一発で)
よくある落とし穴と注意点
-
挿入後にフラグメントは空:挿入後もフラグメント内の要素にアクセスしたい場合は、挿入前に参照を保持しておくか、挿入先から再取得します。
-
イベント/状態の扱い:ノードをフラグメントへ「移動」する場合、ノードに付いているイベントリスナや一部の状態(例えば
valueなど)は維持されます。新規生成のノードには当然リスナが無いので、必要なら挿入前に付与するか、イベント委任を使います。 -
再描画の最小化 ≠ 変更通知が1回になる:
MutationObserverは追加された各ノードを検出します。とはいえ、レイアウト計算はまとめて行われやすいため実効パフォーマンスは向上します。 -
外部ドキュメントからの取り込み:
DOMParserなどで別Documentを作った場合は、document.importNode(node, true)で現在の文書へインポートしてからフラグメントに追加します。 -
アクセシビリティ:大量追加で DOM が急増すると、スクリーンリーダーが一度に多くのノードを認識します。段階的レンダリングや仮想スクロールも検討してください。
ベストプラクティス
-
作るのはオフライン、入れるのは一度:ループ内で親に直接追加せず、まずフラグメントに積む。
-
テンプレートを活用:繰り返し UI は
<template>+content.cloneNode(true)が読みやすくミスが減ります。 -
イベント委任:大量要素に個別リスナを付けず、親にまとめて付けると軽量。
-
計測する:規模によってはブラウザの最適化で差が小さい場合もあるため、
PerformanceAPI などで実測し、必要な箇所にだけ適用する。 -
置換 API を併用:
replaceChildren/before/after/replaceWithはフラグメント(の子)を受け取れるため、段組み・リスト全体の差し替えに有効。
まとめ
DocumentFragment は「オフラインで DOM を組み立て、最後に一気に実 DOM に反映」するための標準的なテクニックです。大量追加、並べ替え、テンプレート展開、HTML 文字列の安全な取り回しなどで効果を発揮します。
描画コスト・コードの見通し・保守性の観点からも、複数ノードの挿入が絡む場面ではまずフラグメントを検討するのが推奨です。
ChatGPT5 生成日:2025/09/11