Orcantus

Postmortem

検証用HTMLを他サービスのページへ注入して計測したら、結論を2件間違えた話

自作のMarkdownエディタで「note.comは見出しや番号付きリストをどう表示するか」を確かめるため、実ページのDOMに検証用のHTMLを注入し、適用されたCSSをcomputed styleで読み取る方法を使いました。結果、2件の結論を間違えました。

結論。他サービスの実ページに検証用HTMLを注入してCSSを計測する方法には、注入したHTMLの構造が実物のDOM構造とわずかに違うだけで適用されるセレクタがずれ、誤った値を読んでしまう欠陥がある。 「note.comはh1を装飾しない」「note.comは番号付きリストの数字を表示しない」という2件の結論はどちらもこの欠陥による誤判定で、実際は「h1はh2に変換される」「番号はCSSカウンタで描画される」が正しかった。実記事のHTMLと配信CSSを直接読む方法に切り替えて訂正した。

何を確かめようとしていたか

Markdownエディタはプレビューをnote風・GitHub風・Zenn風・Qiita風の4テーマで切り替えられる機能を持っており、各テーマの表示は実サービスの実測値を反映する方針で作っています。note.comは公式のMarkdown仕様を公開していない(リッチテキストエディタへの入力時変換のみ)ため、確認は実ページのCSSやHTMLを調べる形になります。

最初に採った方法は、note.comの実記事ページを開いた状態でブラウザの開発者ツールから検証用のHTML断片(<h1>や<ol><li>など)をDOMへ直接注入し、note.com自身のCSSが当たった状態のgetComputedStyleを読む、というものでした。

注入計測が生んだ2件の誤判定

この方法で得た最初の結論は次の2つでした。

どちらも「note風テーマ」の実装に反映しましたが、後日実記事のHTML・配信CSSを直接取得して突き合わせたところ、両方とも誤りでした。

なぜ注入計測は壊れたのか

原因はどちらも同じで、注入したHTMLの構造が実サービスの実際のDOM構造とわずかに違うと、適用されるCSSセレクタがずれるという、この計測方法そのものの欠陥でした。p:beforeのような子孫セレクタは、間に挟まる要素が1つ違うだけで成立しなくなります。「CSSが実際に当たった状態を直接測っている」という事実だけでは、「注入したマークアップが実物と同一である」ことまでは保証されません。

訂正: 実記事のHTMLと配信CSSを直接読む方法へ切り替えた

訂正にあたっては、注入・computed style計測を補助的な確認手段に格下げし、実記事ページが実際に出力しているHTMLと、サービスが配信しているCSSファイルそのものを直接取得して読む方法に切り替えました。これなら「実物のDOM構造」と「実物に当たっているCSSルール」を両方とも実物のまま確認でき、注入によるずれが原理的に起こりません。

GitHubについては公式の変換API(api.github.com/markdown、投稿不要でMarkdown文字列をPOSTすると実パーサーのHTML出力が返る)を使い、実パーサーそのものの出力を取得しました。Zenn・Qiitaは実記事が出力しているHTMLと配信CSS(.znc・.it-MdContent)を直接確認しています。

この方法に切り替えた直後の突き合わせでは2件の誤りを訂正しましたが、それで終わりではありませんでした。続けて実ブラウザでの並べ比較(4テーマのシンタックスハイライト配色がすべて実サービスと一致することをcomputed styleで確認)、さらにOS自体をダークテーマに切り替えた環境での再検証を行ったところ、「note.comはダークモードに非対応」という、それまで前提にしていた理解自体も誤りだったことが分かりました。実際にはnote.comの配信CSSに@media (prefers-color-scheme:dark)が存在し、ログイン不要でダーク表示に対応していました(コードブロックは--color-surface-invertという反転用の変数で組まれており、ダークでは背景が白・文字が暗色に反転するという、通常のダーク実装とは逆の作りになっていたことも実機で確認しています)。1つの方法の切り替えが、派生して別の誤った前提まで洗い出す結果になりました。

読者が同じ手順で確かめる方法

この記事の主張(h1→h2変換、番号のCSSカウンタ描画)を自分で再現するには、以下の手順で確認できます。

  1. note.comの任意の公開記事をブラウザで開き、開発者ツールの「要素」タブで本文領域のDOMを確認する。見出しがすべてh2・h3になっていること、番号付きリストの<li>の直下に<p>が入っていることが見える。
  2. 同じページの「ネットワーク」タブ、または「ページのソースを表示」から配信CSSのURLを特定し、ol > li > p::beforeに相当するルールとcounterの定義を検索する。
  3. 検証用HTMLを注入する場合は、必ず手順1で確認した実物と同じDOM構造(<li><p>...</p></li>)で注入する。構造が違うセレクタ照合は、一致しても偶然、不一致でも誤判定になり得る。

この結果が言っていないこと

  • この記録は自作アプリ(Markdownエディタ)1件の開発ログ(PLAN.md 10節・11節、2026-08-14・08-15時点の確認)を一次資料とするケーススタディであり、「DOM注入によるCSS計測は常に誤る」という一般的な主張ではありません。注入したマークアップが実物のDOM構造と完全に一致していれば、原理的には同じ結果が得られます。
  • note.comの表示仕様(h1→h2変換、CSSカウンタによる番号描画、ダークモード対応)はいずれも2026-08時点の確認であり、note.com自身は公式のMarkdown仕様・DOM構造を公開していません。配信CSS・実記事DOMが変更されれば現在の挙動と異なる可能性があります。
  • GitHub・Zenn・Qiitaについてはこの記事の対象外(10節・11節で別途確認済みですが、ここでは「注入計測の欠陥」というnote.comでの事例に絞っています)。

同じ失敗は、他サービスのDOM構造を直接観測せずに「CSSが実際に当たった値」だけを根拠にすると起こり得ます。計測方法そのものが正しいかを疑う視点が、結論の正しさと同じくらい必要でした。