2
0

More than 3 years have passed since last update.

Chrome で documentFragment をつかって DOM 上に存在しなくなった要素を再度DOMに追加すると表示されないことがある

Last updated at Posted at 2020-04-28

追記(2020-05-25)

Chrome 83.0.4103.61 だともう起きません。

概要

Chrome で documentFragment をつかいつつ appendChild すると存在してるはずの要素が表示されないことがある。

条件

調べた限りだと、以下の全てを満たしてると起きる。

  • Chrome 81.0.4044.122
    • 他のバージョンは調べてない
  • 子要素が隠れる可能性のある要素
  • 一つの関数内で、親要素を空にして子要素をいったんdocumentFragmentにいれてから本物のDOMに追加する処理を行う
  • DOM上にかつて存在したが今は存在していない子要素を追加する

つまり以下のいずれかの条件を満たすと起きない。

  • Firefox
  • 常にブラウザ上に表示される親子要素に対する操作
    • <ul><li> とか
    • <div> とか
    • (要はほぼ全ての要素)
  • documentFragment を使わない
  • document.createElement で新たに作成した要素を追加する
  • 親要素を空にする操作と子要素の追加の操作を、ちょっと時間置いて実行する

example.html
<select id="list">
  <option class="item" value="1">1</option>
  <option class="item" value="2">2</option>
  <option class="item" value="3">3</option>
</select>

上のようなHTMLに対して jQuery で以下の操作を行う。

const $list = $('#list');
const $items = $('.item');

(() => {
  // リストを空にする
  $list.empty();
  // DOM上には存在しなくなった items を再度 append する
  $items.each((index, el) => $list.append(el))
})()

すると開発者ツールの Elements タブでは存在して見えるのに、ブラウザ上では表示されなくなる。 <select> 要素をクリックしても何も出てこなかったり、2, 3 だけ出てきたりして不審な挙動を起こす。

append.png

jQuery を使ってなくても以下のようにやると再現する。 jQuery append も内部で document.createDocumentFragment() をつかってるので fragment の挙動がなんかおかしいっぽい。

const list = document.querySelector('#list');
const items = document.querySelectorAll('.item');

const append = (parent, child) => {
  const fragment = document.createDocumentFragment();
  fragment.appendChild(child);
  parent.appendChild(fragment);
}

(() => {
  // リストを空にする
  list.innerHTML = '';
  // DOM上には存在しなくなった items を再度 append する
  items.forEach( item => append(list, item) );
)();

解決策

どうやら appendChild したあとにレイアウト(リフロー)が起きてないっぽい。なのでリフローすればよい。見えなくなった要素の高さを取得したり、開発者ツールでハイライトしたりするとリフローが起きて表示される。

もしくは DOM を使い回さない。適宜 createElement などする。

// 高さを取得したり
item.offsetHeight
// jQueryならcloneしたりで要素を作り直してやるとか
$items.each((index, el) => $list.append($(el).clone()))

リンク集

2
0
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
0