フラグメント利用で描画高効率化 — const frag = document.createDocumentFragment(); frag.append(...)
大量の要素を1つずつDOMに挿入すると、そのたびにレイアウト計算や再描画が発生して重くなります。DocumentFragment にまとめて追加してから、最後に親へ一括挿入すると再描画の回数を減らせて高速になります。
基本の使い方
<ul id="list"></ul>
<script>
const ul = document.getElementById("list");
// 1) 空のフラグメント作成
const frag = document.createDocumentFragment();
// 2) 子要素をフラグメント側にどんどん追加
for (let i = 1; i <= 5; i++) {
const li = document.createElement("li");
li.textContent = `Item ${i}`;
frag.append(li); // appendChildでもOK
}
// 3) 最後に親へ一括挿入(ここで初めて画面に現れる)
ul.appendChild(frag);
</script>
HTML- 効果: メモリ上のフラグメントに溜めてから1回の挿入で済むため、再レイアウト・再描画の回数を削減できます。
なぜ速いのか(ポイントだけ)
- フラグメントは“画面外の入れ物”: DOMツリーの一部ではないため、フラグメントへ追加してもページの再描画は走りません。最後の1回の挿入でまとめて反映されます。
- 移動の挙動: フラグメントに追加された子ノードは、フラグメントをDOMに挿入するとフラグメントから取り出され、親へ“移動”します(複製ではない)。
よく使うテンプレート集
ラベル: 大量リストの高速生成
function renderList(parent, items) {
const frag = document.createDocumentFragment();
for (const text of items) {
const li = document.createElement("li");
li.textContent = text;
frag.append(li);
}
parent.appendChild(frag);
}
renderList(document.querySelector("#list"), ["A", "B", "C", "D", "E"]);
JavaScriptラベル: ネストしたカードUIをまとめて作る
function createCard({ title, desc }) {
const article = document.createElement("article");
article.className = "card";
const h = document.createElement("h3");
h.textContent = title;
const p = document.createElement("p");
p.textContent = desc;
article.append(h, p);
return article;
}
const frag = document.createDocumentFragment();
[
{ title: "お知らせ", desc: "年末は休業します" },
{ title: "更新", desc: "バージョン2.0を公開" },
].forEach(data => frag.append(createCard(data)));
document.getElementById("app").appendChild(frag);
JavaScriptラベル: innerHTML ではなく安全にDOMで構築
const frag = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
const div = document.createElement("div");
div.className = "row";
const b = document.createElement("b");
b.textContent = `Row ${i + 1}`;
div.append(b);
frag.append(div);
}
document.querySelector("#rows").appendChild(frag);
JavaScript実務でのコツ
- ラベル: 小分けしてから一括挿入
- ループ内で親へ直接
appendChildせず、まずフラグメントに溜める。その後に1回だけ親へ追加。
- ループ内で親へ直接
- ラベル: 既存DOMの差し替えにも使える
- 新しいフラグメントに作り直してから、古い子をクリアして差し替えると見通しがよく、ちらつきも抑えられます。
- ラベル: APIの選択
document.createDocumentFragment()で作成。appendもappendChildも使える。最後の親への挿入はappendChild(frag)が分かりやすい。
ありがちなハマりポイントと対策
- ラベル: 途中で親へ挿入してしまう
- 対策: ループで毎回挿入すると非効率。必ずフラグメントに溜めて最後に1回。
- ラベル: 複製されると勘違い
- 対策: フラグメントの子は“移動”される。フラグメント自体は空になる(その後再利用も可)。
- ラベル: イベントの付与忘れ
- 対策: 作成中に
addEventListenerを付けてからフラグメントへ入れる。後付けでもOKだが、作成関数内で完結させると漏れない。
- 対策: 作成中に
練習問題(手を動かして覚える)
<ul id="list"></ul>
<button id="add100">100件追加</button>
<script>
const list = document.getElementById("list");
document.getElementById("add100").addEventListener("click", () => {
const frag = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
const li = document.createElement("li");
li.textContent = `Item ${i + 1}`;
frag.append(li);
}
list.appendChild(frag); // ここで初めて100件が一気に挿入
});
</script>
JavaScript- 効果確認: 100件を1つずつ挿入するのと比べ、スクロールや描画が滑らかになるのを体感できます。
直感的な指針
- “作るのはフラグメント、見せるのは最後に1回”が基本。
- 大量生成・差し替え・ネスト構築に強い。
- 安全なDOM組み立てと合わせて、再描画を減らして体感速度を上げる。
