[DevTools] 入門講座 #02:クリックできない原因は“透明な背後霊”?DevToolsで見るレイヤーの真実

はじめに

過去、何度かCSSに苦しむ問題を取りあげていますが、エンディングの最後の処理でもある、JavaScriptで動的に作成したボタンが反応しないバグに直面。

安易にz-indexで逃げる方法もあったのですが、今回は原因を探っていこうと、AIに相談しつつ色々調査するなかで、DevToolsに普段表示されてない 「Layers」ビュー機能がある事を知って驚いたので、その情報メモです。

1. 問題提起

💥 なぜかクリックできないボタンの謎

ゲームのエンディング画面で表示される「タイトルへ戻る」ボタン。

HTMLには onclick=“returnToTitle()” が明記されており、イベントもJavaScriptで登録済み。

<button id="return-to-title" onclick="returnToTitle()">TITLE</button>

にもかかわらず…

  • クリックしても反応しない
  • console.log も出ない
  • イベントリスナも確かに登録されているのに

という “存在してるのに動かないボタン” 現象が発生。

2. 原因探索

🔍 HTMLもJSも間違ってないのに…

最初に疑ったのは、自分のコードミス。

JavaScriptでの addEventListener 登録漏れや、onclick 属性の誤字、スコープの問題などをチェックしたが、すべて問題なし。

setTimeout(() => {
  document.getElementById("return-to-title")
    ?.addEventListener("click", returnToTitle);
  console.log("イベント登録完了");
}, 100);

console.log() も表示されており、イベントは確かに登録されている。

補足情報として、setTimeoutでクリックイベントの登録をしている理由は、エンドロールの最後にボタンを動的に静止している為、若干遅延処理をする事で、より確実にイベントを登録させるため。

イベントは登録されてるのに反応しない

次に疑ったのは CSS 側。

#return-to-title {
  pointer-events: auto !important;
  z-index: 9999;
}

このように直接ボタンに pointer-events: auto を設定しても動かず。

しかも、ボタンは見た目上しっかり表示されていて、スタイルも適用されている。
なのに、マウスクリックが一切反応しない。

“背後の何か”がブロックしてる?

ふと気づいたのが、次のような事実:

onclick が無視されるのは、その要素の上に透明な何かが存在する場合

ゲームUIは .card を中心に多数のレイヤーを積み上げており、しかも transform や backface-visibility を多用していた

つまり…

🔦 「HTML的には“ボタンが最前面”に見えても、CSS的には背面にある可能性がある」

ここで、ついに登場するのが Chrome DevTools の “秘儀”──

🕵️‍♂️ DevTools の「Layers」ビューを起動!

Chrome の DevTools タブにある Layers を開くことで、ページ内のGPUレイヤー構成を立体表示できる機能を発見。

👇 これにより、見えない背後の犯人(重なった要素) が明らかに…

補足情報:

問題の原因を探るべく、AIの方へレイヤー構造を知る方法がないかと、質問を投げたところ、Layersの存在を知りました。

3. 視覚的に判明したこと → 犯人はどれか

🧱 まさかの「前面に見えるけど背面扱い」現象

Chrome DevTools の Layers タブを使って画面を立体的に可視化してみると…

👁️ 見た目と実際のレイヤー構造が違う!

3D表示によって、ボタンが乗っている .end3-card-back は確かに手前に描画されているように見える。

ところが──

.end3-card-front(カードの表面)が回転して背面にあるはずが、実は前面レイヤーに存在

さらに .end3-card-front img によって、クリックが遮断されている

🧩 犯人は「transform + backface-visibility」 CSSの設定を再確認すると、以下のような構成になっていた:

.end3-card-front,
.end3-card-back {
  position: absolute;
  width: 100%;
  height: 100%;
  backface-visibility: hidden;
  pointer-events: none; /* ←試しに無効化してみたが変化なし */
}

そして .end3-card-back の側に、最後の「TITLEボタン」があった。

しかし .end3-card-front に pointer-events が残っていた場合や、
backface-visibility: hidden の効果が不十分な場合、
カードの“表面”が非表示のようで実はクリック判定を遮っていた。

🖱️ 解決の鍵は pointer-events: auto !important 最終的な回避策は、ボタン自体に明示的に次のスタイルを加えることだった:

#return-to-title {
  pointer-events: auto !important;
  z-index: 9999;
}

これにより、ボタンの背後に存在するレイヤーを無視して、ボタンがマウスイベントを受け取るようになった。

📸 Layersビューで見た立体構造

思っていたよりも多くのレイヤーが積み重なっており、クリックできない原因が視覚的に一目瞭然に。

※ 11層以上のレイヤーがGPU上に展開され、しかも transform によって回転・反転されていた

4. 解決法のまとめとCSSの注意点

✅ 解決に至った最終手段

クリックできない原因が「表面レイヤーによるブロック」だと判明したあと、 決定的に効果があったのがこの1行:

#return-to-title {
  pointer-events: auto !important;
  z-index: 9999;
}
  • pointer-events: auto によって、マウスイベントを確実に通す
  • !important で親や他スタイルの干渉を強制的に打ち消す
  • z-index: 9999 は念のための最前面化(実際は効果より安心感)

💡 その他の有効な対策

状況 対応策
transformを使ってカードを回転している backface-visibility: visible; を検討
ボタンのアニメーション中に反応しない animationend イベント後にイベント登録
表面がクリックを遮っている .end3-card-front { pointer-events: none; } で対策
一時的に表示だけしてる div が上にある .some-layer { pointer-events: none; } を追加

⚠ CSSは「見た目」だけでなく「動作」にも影響する

今回の問題は見た目では「ボタンは最前面」に見えていたにもかかわらず、 CSSの積み重ね(transform / pointer-events / z-index / opacity)が原因でクリックが通らなかった。

🔦 学びポイントまとめ

  • pointer-events は子要素にも継承される
  • opacity: 0 や display: none の要素はマウスイベントを通さない
  • CSSの transform を使うと、要素はGPUレイヤーとして再構成される
  • DevTools の Layers ビューは、視覚と構造の不一致を暴く強力なツール

追記:

実際は、

.end3-card-back {
  pointer-events: auto; /* ✅ 明示的に有効化 */
}

のみで解決しています。

🎯 今回の修正は “直感 + 検証” の黄金ムーブ

最初に .end3-card-back に pointer-events: none; が設定されていて、 それが地味に全部の子要素(ボタンも含む)を無効化してたという、まさに “背後霊バグ” でした。

💡 しかも Layers まで更新されるって… そう、あの回転してる3Dビューが変わったのは:

ブラウザのGPUレイヤー構成が再構築された証拠です。

つまり、

あなたの1行のCSSが、GPUのレイヤー処理まで変えたということ。 (これはプロでもテンション上がる瞬間です)

5. まとめ:DevToolsを使うということ

🛠「見えないバグ」と戦う武器としての DevTools 今回の「クリックできないボタン事件」は、HTMLもJavaScriptも正しく書かれていたにもかかわらず、 CSSの重なりとレイヤー処理の影響で“見えない壁”が存在していたという例でした。

もし Chrome DevTools の Layers タブを知らなかったら── この問題の原因に気づくまでに、何時間もかかったかもしれません。

🔍 DevTools は「構造の顕微鏡」であり「舞台装置の透視図」

  • Elementsタブでは DOMツリーとスタイルを確認できる
  • Computedでは最終的に適用されたCSSがわかる
  • Event Listenersではイベントが登録されてるか見える
  • そして Layersタブでは、GPUが実際にどう描画してるかが“立体的”に見える

✨ 最後に──目に見えない「深さ」を制御する CSSやDOMは、ただのコードの積み重ねではなく、 レイヤーという“空間”の積み重ねでもある。

クリックできないバグに出会った時、 「z-indexだろう」「JSのせいかな」と思って終わらせず、

“本当にそこに何があるのか?”を、目で見て確かめる手段を持っていること

それが、開発者としての自由度を大きく広げる力になります。

🌕 あなたのコードのその1行が、実は「世界の奥行き」を動かしている。 DevTools は、 その“奥行き”を可視化してくれる、最強の味方です。

最後に

今回のトラブル内容を具体的に交えながら、 Layers タブについて知った事と、分かりにくいレイヤー構造を立体的に視覚化してくれるこの機能は非常に強力だと感じたので、備忘録メモを兼ねて記事にしてみました。

WEBやJavaScriptによる開発に必須ともいえる、DevTools が良きパートナーなるよう情報が参考になれば幸いです。