画像ギャラリーに並べ替え(シャッフル)を足して、PC のブラウザで一通り確かめ終えたときのことです。何度並べ替えても、画像は普通に並び直しました。ところが iPhone の Safari で同じページを開くと、並べ替えたあとの画像がいつまでも空白のままでした。再読み込みすれば表示されます。並べ替えの直後だけ、読み込みが始まらないのです。
個人開発でサイトを運用していると、こういう「手元では再現しない」不具合に、年に何度かぶつかります。最初にお伝えしたいのは、この種の不具合は、AI に聞く前の材料集めで、答えの精度がほとんど決まるということです。以下では、私自身が Dolice のサイトで経験したこの件を例に、材料の揃え方を整理します。
起きたことを、事実だけ先に書きます
確認できているのは次の点です。
- 遅延読み込みの画像を並べた一覧を、スクリプトで並べ替える(要素を別の位置へ移動する)と起きます
- iPhone の Safari 単体で起きます。PC のブラウザでは再現しません
- 並べ替えたあとの画像が、二度と読み込まれません
- アプリ内のブラウザ(WebView)では確かめていないため、そちらは「未確認」です
一方で、なぜ Safari だけで起きるのか、ブラウザ内部の仕組みまでは追っていません。仕様書や Safari のソースを読んで裏づけたわけではないので、原因の説明は書かないことにしました。「移動した要素の読み込み判定が走り直されない状態になっているのかもしれません」という推測は持っていますが、推測のままです。
直し方は、移動のあとに自前で読み込みを起こす形にしました
直した方針は一つだけです。並べ替えて要素を動かしたあとに、ブラウザの遅延読み込みに任せず、自分の可視判定で画像の読み込みを起動するようにしました。確認は、実機の iPhone で並べ替えを繰り返して行っています。
次のコードは、その考え方を示す例です。私のサイトの実コードそのものではなく、Safari での動作を保証するものでもありません。お手元の端末で確かめてください。
// 並べ替えのあとに呼びます。画面の近くにある画像だけ、自分で読み込みを起こします。
// data-src に本来の URL を持たせておく構成を想定した例です。
function wakeVisibleImages(container, margin = 200) {
const vh = window.innerHeight;
container.querySelectorAll('img[data-src]').forEach((img) => {
const r = img.getBoundingClientRect();
if (r.bottom < -margin || r.top > vh + margin) return; // 画面から遠い画像には触らない
img.src = img.dataset.src;
img.removeAttribute('data-src');
});
}
// 並べ替えの本体(再現用の最小例)
function shuffle(grid) {
const items = [...grid.children];
items.sort(() => Math.random() - 0.5).forEach((el) => grid.appendChild(el));
wakeVisibleImages(grid); // 移動の直後に呼ぶ
}画面から遠い画像まで一斉に読み込むと、遅延読み込みを入れた意味が消えます。そのため、margin で近さの範囲を絞っています。
AI に診断を頼む前に、揃える 4 つの材料
この不具合の原因を Gemini のような AI に尋ねるなら、次の 4 つを先に手元で揃えておくと、返ってくる答えの質が変わります。なお、この件で私が実際に AI に尋ねたわけではありません。ここから先は、同じ状況の方が試すときの進め方として書いています。
- 環境の特定:端末、OS の版、ブラウザの種類。「Safari 単体」と「アプリ内ブラウザ」を分けて書きます
- 再現する条件としない条件:「PC では再現しない」という事実は、そのまま重要な手がかりです
- 直前に行った操作:この件では「要素の移動」でした。症状の画像より、その直前の操作のほうが原因に近い場合があります
- 最小の再現コード:サイト全体ではなく、10 行前後に削ったもの
材料が揃っていれば、依頼文は短くて済みます。
【環境】iPhone の Safari(アプリ内ブラウザは未確認)。PC のブラウザでは再現しません。
【症状】遅延読み込みの画像を並べた一覧を、スクリプトで並べ替えたあと、画像が二度と読み込まれません。再読み込みすると表示されます。
【直前の操作】子要素を appendChild で別の位置へ移動しています。
【再現コード】(10 行前後の最小例を貼る)
【知りたいこと】原因として考えられるものを、確度の高い順に。確かめる方法も一緒に。「確度の高い順に」「確かめる方法も一緒に」と添える理由は、返ってきた推測をそのまま採用しないためです。AI の答えは、実機で確かめるまでは仮説として扱います。
実機で確かめるときの小さな工夫
実機の確認は、手順を決めておくと迷いません。私は、並べ替えを 5 回ほど続けて押し、毎回、画面を上下にゆっくりスクロールして、空白の画像が残っていないかを目で見ています。一度で判断せず、回数を重ねるのは、たまたま読み込まれた回を「直った」と取り違えないためです。画像の読み込み全般の見直しは、Core Web Vitals を自動診断する記事でも触れています。
失敗から引いた線引き
この不具合は、PC のブラウザだけで確認を済ませていたら、気づけませんでした。画面の上では全部が正しく動いているように見えるからです。症状を AI に説明しようとして初めて、いま思えば当たり前のことですが、「どの環境で確かめたか」が自分の頭の中にしか無いことに気づきます。
確認した環境を言葉にできないうちは、AI に対しても自分に対しても、「直りました」とは言いません。 この線引きだけは、これからも守ってまいります。
次の一歩
お手元のサイトで、遅延読み込みの画像を動かす処理(並べ替え、絞り込み、無限スクロール)を一つ選び、実機の iPhone の Safari で試してみてください。再現したときは、上の 4 つの材料をメモに残してから、AI に尋ねていただければ幸いです。同じ種類の「調べる前の準備」は、クラッシュ報告を毎回ゼロから読ませない運用でも書いています。