広告ブロック検知をアクセス制御へ使うと、拡張機能以外の通信障害まで読者の責任として扱いかねません。このブログでは、広告を確認できない場合も本文を隠さず、再試行できる小さな通知を表示します。判定は一度のDOM確認ではなく、有限時間の状態機械として実装しています。
この記事はブロッカーを回避・難読化する方法ではありません。広告配信失敗の誤判定を減らし、読者の選択を残す実装記録です。
広告スクリプトの読み込みとエラー、猶予タイマー、広告風要素確認から広告表示または非遮断通知へ分岐する状態機械*図: DOM要素の有無だけで即断せず、スクリプトのライフサイクルと有限猶予後の状態を合わせて判定する。どちらの分岐でも記事は開いたままにする。*
全画面ゲートにしない理由
広告スクリプトが読めない理由は、拡張機能、DNSフィルタ、企業ネットワーク、CSP、オフライン、読み込み遅延など複数あります。ブラウザ上のシグナルだけで原因や拡張機能名を断定することはできません。不確実な判定で本文まで塞ぐと、広告を許可している読者も巻き込みます。
そのため通知は右下へ固定した小さなパネルにし、背景側の記事とナビゲーションは操作できるままにします。通知には role="status" と aria-live="polite" を付けます。モーダルダイアログとしてフォーカスを奪ったり、背景をinertにしたりはしません。
実装した4つのシグナル
- 広告風要素が
display:none、visibility:hidden、または0寸法になっていないか確認する。 - AdSenseの読み込みスクリプト要素が存在するかではなく、
load と error のライフサイクルを記録する。 - hydration直後に決めず、450ms、1500ms、3500msの猶予後に再判定する。
- スクリプトが遅れて正常化した場合は通知を解除する。
スクリプト要素がDOMに残っていてもネットワークエラーで失敗することがあります。逆にhydration時点でスクリプトがなくても、同意状態や設定取得後に挿入されることがあります。DOMの存在だけを根拠にせず、複数シグナルを有限時間だけ組み合わせるのが要点です。
読者に残す2つの操作
通知には「広告を再試行」と「記事を読み続ける」を用意します。再試行はページをreloadして広告スクリプトを最初から評価します。読み続けるを選んだ場合は通知だけを閉じ、本文表示には影響しません。
許可方法の詳細は折りたたんでおき、必要な読者だけが開けるようにします。特定の拡張機能を使っていると断定せず、許可する場合もこのホストだけをallowlistへ入れる選択肢として案内します。
監視を無期限にしない
MutationObserver は document.head だけを対象にし、5秒で切断します。タイマー、オブザーバー、スクリプト listener、広告風要素はアンマウント時にすべて解放します。document.body 全体を永続監視すると、記事中の変更まで拾って性能と予測可能性を損ないます。
再試行はwindow.location.reload()でページ全体を読み直し、同じ検知手順を最初から実行します。個別スクリプト URLへretry識別子を付けたり、広告ブロッカーをすり抜けるためにURLやclass名を難読化したりはしません。
UIとポリシー上の境界
通知は広告表示がブログ運営の支援になることを説明しますが、広告クリックは依頼しません。ナビゲーションに見せかけた広告も置きません。検知結果から拡張機能名を推測・収集せず、個人識別やfingerprintingにも使いません。
Google AdSenseの回復messageを併用する場合は、自作通知との二重表示を避けます。AdSense側の選択肢と公開状態は管理画面で確認し、このサイトの非遮断方針と矛盾しない構成にします。
回帰テスト
- 猶予前には通知を出さない。
- 広告風要素が見え、読み込みスクリプトが正常に読み込みした場合は通知を出さない。
- スクリプト要素が存在しても
error イベントなら配信失敗として通知する。 - 遅れて読み込みスクリプトが正常化したら通知を解除する。
- オブザーバーはheadだけを監視し、期限後とアンマウント時に切断する。
- 通知はpoliteな状態として認識でき、modal属性を持たない。
- 「記事を読み続ける」で通知だけを閉じられる。
この仕様は広告が必ず表示されることを保証するものではありません。誤検知時にも本文を人質にせず、検知処理のリソースを有限に保つための境界です。
公式参考資料
関連記事