Matomoヒートマップでページの一部が切れる原因と修正方法

Matomoのヒートマップスクリーンショットは、スクロールコンテナやoverflow:hiddenのラッパー内のコンテンツを黙って切り捨てます。サイドバー、モーダル、「スクロールテリング」レイアウトは表示端より先が消え、クリックはキャプチャ時に画面にあったものの上に落ちます。なぜそうなるのか、どう対処しているかを解説します。

Matomoのヒートマップを開いたら、サイドバーが途中で切れていた、モーダルの下半分が消えていた、クリックマーカーが全然関係ないコンテンツの上に浮いていた——そういう経験があるとしたら、クリック自体は問題ありません。Matomoは正しい座標に記録しています。壊れているのはその下のスクリーンショットです。ページのどこかのラッパーに overflow: hiddenoverflow: auto、または overflow: scroll が設定されていて、Matomoのレンダラーはそのラッパーの表示端より先にあるものを存在しないものとして扱います。結果、訪問者が実際に見ていたページではなく、ページの一部だけが切り取られてヒートマップに表示されます。

最も手早い修正方法は、私たちが管理している無料のChrome拡張機能、Matomo Heatmap Helperです。各キャプチャの直前にoverflowコンテナを無効化してレンダラーがドキュメント全体を見えるようにし、キャプチャ後に元のスタイルを復元します。この記事の残りは、拡張機能を使わずに同じことをする方法と、コードに組み込む価値のある恒久的な修正方法です。

拡張機能なしで修正する方法

キャプチャ直前に問題を一時的に解決するコンソールのスニペットと、サイトに組み込める恒久的な修正方法がいくつかあります。作業している制約に合ったものを選んでください。

ページ上のoverflow制限要素をすべて確認する

何かを変更する前に、どのラッパーがコンテンツをクリップしているか調べましょう。ChromeでページをOpen し、F12でDevToolsを開いてConsoleタブに切り替え、以下を貼り付けます:

js
// コンテンツをクリップしている要素をすべて列挙する
Array.from(document.querySelectorAll('*')).filter(el => {
  const s = getComputedStyle(el);
  return ['hidden','auto','scroll'].includes(s.overflow)
      || ['hidden','auto','scroll'].includes(s.overflowY);
});

これでMatomoのレンダラーが固定サイズのボックスとして扱うノードの正確なリストが得られます。よくある犯人はサイドバー、モーダル、<main> を囲むカスタムスクロールラッパー、そして何年も前に意味がなくなったレイアウト目的で overflow: hidden を持ち続けているclearfixのラッパーです。

手早い修正:コンソールからoverflow制限を取り除く

これはMatomoのヒートマップキャプチャをトリガーする直前にブラウザコンソールに貼り付けるスニペットです。現在クリップしているすべての要素を辿り、overflowoverflow-yvisible に変えます。MatomoがDOMをシリアライズする時点では、表示端より先に何かを隠している要素はありません。

js
// キャプチャ直前にブラウザコンソールに貼り付ける。
// ページ上のすべてのoverflowコンテナを'visible'に変える。
document.querySelectorAll('*').forEach(el => {
  const s = getComputedStyle(el);
  if (['hidden','auto','scroll'].includes(s.overflow) ||
      ['hidden','auto','scroll'].includes(s.overflowY)) {
    el.style.overflow = 'visible';
    el.style.overflowY = 'visible';
  }
});

ページが一瞬おかしな見た目になります。サイドバーはコンテンツの全高に広がり、モーダルはビューポートの端を突き抜け、固定高さのコンテナに依存していたものがコンテナを失います。それで構いません。サイトを閲覧しているのではなく、ヒートマップをキャプチャしているのですから。終わったらリフレッシュしましょう。

これが手早い方法です。一度きりのキャプチャや、コードの変更を待たずに今すぐきれいなスクリーンショットが必要なレビューサイクルで機能します。定期的に再キャプチャするものには、以下の恒久的な修正方法のどれかを組み込みましょう。

キャプチャモードにスコープした恒久的なCSS修正

スタイルシートを管理できるなら最もきれいな答えは、Matomoのトラッカーが読み込まれた瞬間にすべてのoverflowコンテナをオフにするヒートマップ専用のオーバーライドです。CSSブロック一つとJS一行で完了します。

css
/* セレクタをサイトのラッパーに合わせて編集してください */
html.heatmap-mode .sidebar,
html.heatmap-mode main,
html.heatmap-mode .modal-shell {
  overflow: visible !important;
  overflow-y: visible !important;
  height: auto !important;
  max-height: none !important;
}
js
// サイトに追加してください。Matomoのトラッカーがページにある場合にクラスを切り替えます。
if (window._paq) document.documentElement.classList.add('heatmap-mode');

これでオーバーライドはMatomoが読み込まれているページだけに効き、ヒートマップのレビューには問題なく、他のトラフィックには見えません。さらに絞り込みたい場合は、クエリパラメータ(?heatmap=1)や、Matomoの向き先にしているステージング環境だけに含まれる別のスタイルシートで制御できます。

ネストされたスクロールコンテナを完全に取り除く

「スクロールテリング」目的でページの <main> や別のラッパーに overflow: auto がついている場合、アーキテクチャとしての修正はそれを取り除いてドキュメントをスクロールさせることです。Matomoのレンダラーはドキュメントスクロールは再現できますが、ネストされたスクロール位置は再現できません。モバイルUXも改善します(iOS Safariはネストされたスクロールコンテナに独自の意見を持っています)し、キーボードスクロールとスクリーンリーダーのナビゲーションがユーザーが期待するように動くようになってアクセシビリティも向上します。

CSSのオーバーライドより大きな変更ですが、次に誰かがレイアウトに新しいセクションを追加してもこの問題が再発しない修正方法です。

clearfixの overflow: hiddendisplay: flow-root に置き換える

overflow: hidden を持つ古いclearfixのラッパーは、floatした子要素を包含するための回避策でした。display: flow-root は何もクリップせずに同じことをし、2018年以降サポートする価値のあるすべてのブラウザで安全に使えます。

css
/* セレクタをclearfixラッパーに合わせて編集してください */
.row-with-floats {
  display: flow-root;
}

同じ包含動作、クリッピングなし、スクリーンショットとの戦いも終わります。候補を見つける手早い方法は、CSSで overflow: hidden をgrepして、それぞれが実際に何かをクリップするつもりなのか確認することです。ほとんどの場合、そうではありません。

トレードオフについて

どの恒久的な修正を選んでも、オーバーライドはスコープを絞ってください(クラス、クエリパラメータ、ヒートマップ専用スタイルシート)。ライブのスタイルをすべての人に向けて変えるのではなく、あなたが設計したレイアウトを訪問者には見せ続け、自分のボックス内でスクロールするはずのモーダルはそうであり続けるべきです。オーバーライドはMatomoがページを指すレンダラーのためだけに存在すれば十分です。

Matomoがoverflowコンテナをレンダリングできない理由

Matomoのスクリーンショットキャプチャは2段階のプロセスです。まず、トラッカーがライブDOMをHTMLにシリアライズして送信します。次に、MatomoサーバーがそのHTMLを固定のビューポートで再レンダリングして、ヒートマップビューに表示されるスクリーンショットを生成します。ブラウザセッションなし、訪問者からのスクロール位置の引き継ぎなし、JSによるレイアウト調整なし。別のIPから HTMLファイルをコールドレンダリングするだけです。

レンダラーはドキュメントスクロールは再現できるので、長いページは問題なくキャプチャされます。再現できないのは、ネストされた overflow: auto コンテナの内側のスクロール位置です。それは訪問者のブラウザに存在していて、シリアライズされたDOMには含まれません。レンダラーが overflow: hidden のラッパーにぶつかると、すべてのブラウザと同じようにクリップします。結果は、ある特定の瞬間のページの表示スライスのようなスクリーンショットで、それ以外はすべて消えています。

クリック座標がさらに状況を悪化させます。Matomoはクリックをドキュメント基準で記録し、ユーザーがスクロールしていたコンテナの内側のスクロール位置基準ではありません。スクロール可能なサイドバーの3番目のアイテムへのクリックは、クリックした瞬間にそのアイテムが占めていたy座標に保存されます。レンダラーがサイドバーをscroll-top ゼロでスクリーンショットすると、そのy座標は今や1番目のアイテムのものです。マーカーはそこに描かれます。クリックが間違ったリンクに落ちたように見えます。

実際に何が失敗しているか

よく遭遇するパターンをいくつか:

  • 固有のスクロールバーを持つサイドバーとモーダル。ラッパーが固定高さと overflow: auto を持ち、内側のリストがより長く、キャプチャ時に見えている部分だけがスクリーンショットに入ります。
  • <main> や同様のラッパーに overflow: auto が設定された「スクロールテリング」ページ。bodyはスクロールせず、内側の要素がスクロールし、ヒートマップはビューポート1つ分のコンテンツをキャプチャします。
  • 実際には何もクリップするつもりのない overflow: hidden を持つレガシーclearfixラッパー。floatを包含するためのものでした。今もクリップし、今もスクリーンショットからコンテンツを落とし続けています。
  • overflow: hidden と高さのトランジションでコンテンツをクリップしてアニメーションするカスタムドロップダウンメニューやアコーディオン。Matomoが見るのは閉じた状態です。
  • コンテナへのCSSの mask または clip-path。プロパティは違いますが、スクリーンショットへの影響は同じです。修正方法も同じで、キャプチャモードではオフにします。

ヒートマップでコンテンツが欠けているか、クリックマーカーが期待する要素と一致しないなら、これらのうち少なくとも1つに当たっています。同じページで複数が重なっていることも多いです。

これはフォント、画像、スティッキーヘッダーが同じスクリーンショットで壊れる問題と同じ系統の問題でもあります。残りの問題についてはMatomoヒートマップスクリーンショットが壊れる問題についての詳しい記事があります。また、フォントが読み込まれない理由画像が読み込まれない理由についての個別の記事もあります。それぞれほぼ同じくらいの頻度で発生します。

私たちが実際にやること

スタイルシートを管理できるなら、ヒートマップ専用のオーバーライドを組み込みましょう。Matomoのトラッカーが読み込まれたときにONにするクラスにスコープしたCSSブロック一つ。問題を恒久的に解決する最小の差分で、訪問者が見るものには何も触れません。

他の理由でも問題になっていたネストされたスクロールコンテナがレイアウトにあるなら、アーキテクチャとしての修正をとってドキュメントをスクロールさせましょう。以降のすべてのヒートマップキャプチャでこの問題から解放され、モバイルユーザーにも感謝されます。

どちらも無理な場合(スタイルシートへのアクセスなし、変更できないサードパーティのウィジェット、カスタムCSSを組み込めないCMS)、スタックを変更できないクライアントサイトで私たちが使っているのがMatomo Heatmap Helper Chrome拡張機能です。スニペットが見つけるのと同じoverflowコンテナを辿り、キャプチャのために無効化して、その後復元するので、次の訪問者のためにページは元のままです。無料、オープンソース、コードはGitHubに公開しています

Martezは拡張機能が生まれた大きなプロジェクトです。MatomoをMeta AdsとGoogle Adsに接続して、ROAS、CLV、アトリビューションを別のスプレッドシートではなくウェブ分析の隣に置けるようにします。現在プライベートベータ中です。ご興味があればウェイトリストにご登録ください

ほとんどの場合、スタイルシートの変更一つで解決します。一度やれば済む話です。

Related Articles

Matomoヒートマップでページの一部が切れる原因と修正方法 - Martez Blog