元の HTML
変更後の HTML

HTML Diff: 2つのHTMLファイルをオンラインで比較

2つのHTMLドキュメントを貼り付け、整形し、並べて比較。タグ対応のシンタックスハイライトとライブのwell-formed検証を内蔵。

HTML diffツールとは?

2つのHTMLドキュメントを比較するための、ブラウザ内で動作する無料ツールです。ランディングページの旧版を左に、新版を右に貼り付けると、変更がタグごと、属性ごとに浮かび上がります。アップロードはありません。

diff自体は文字レベルです。各ペインのFormatボタンは、PrettierやHTML Tidyのように一貫したインデントでHTMLを整形し直します。シンタックスハイライトはWHATWG HTML Living Standardに従うので、void要素、boolean属性、エンティティ参照すべてがdiffを読みながら正しく表示されます。

マーケティングページのコピー修正をリリースして、heroセクションのクラス名がなぜ一緒に変わったのかを突き止めるのに1時間溶かした経験があるなら、これはそれを数秒で表面化させるツールです。普通の文章なら、テキストdiffが適切です。HTMLの厳格な親戚であるXMLには専用のXML diffがあります。Markdownは静的サイトビルドでHTMLにコンパイルされることが多いので、Markdown diffも役立つ隣人です。

diffの実際の仕組み

これはHTML対応のシンタックスハイライト付きのテキストレベルdiffであって、DOM diffではありません。比較は文字レベルで動作し、その後の意味的な後処理パスがハイライトをずらして、無作為な記号ではなくタグ名・属性値・可視テキストに乗るようにします。挿入は右ペインに緑、削除は左ペインに赤で表示されます。

HTMLには人々が記憶している以上の解析上のクセがあり、その大半は2つのファイルをテキストとして比較するときにだけ問題になります。解析アルゴリズムによれば、属性順は意味を持たず、属性のクオートは値によってシングル・ダブル・なしのいずれもあり得て、タグ名と属性名は大文字小文字を区別しません。テキストdiffはそれでもすべての並び替えと大文字小文字の入れ替えを表示します。実用的な対処法は、両側を同じツールで整形することです(parser: "html"のPrettierが有効)。これでdiffを読む前にペインが正規化されます。

このツールはドキュメントをDOMツリーに解析してノードを比較しません。つまり、ブラウザで同じように描画される2つのファイル、例えば<img src="a.png">のものと<img src='a.png' />のものでも、ここでは違うものとして表示されます。本当の構造比較が必要なら、両側をDOMParserで解析して自分でツリーを歩くか、両方を先にTidyにかけてください。コードレビューのユースケースの95%(コピー修正、属性の入れ替え、aria-labelの追加)にとって、テキストdiffのほうが速くて分かりやすいです。

3ステップでHTMLを比較

テキストペイン2つ、diff1つ。登録もアップロードもサーバーへの往復もありません。

  1. 1

    HTMLを貼り付けるかアップロード

    古いHTMLを左に、新しいHTMLを右に貼り付けます。あるいは、どちらかのアップロードから.html.htm.emlファイルを直接読み込みます。サンプルボタンは小さなランディングページのスニペットで両ペインを埋めます。先にツールの動きを見たいときに使ってください。

  2. 2

    公平な比較のため両側を整形

    各ペインのFormatを押して、一貫したインデントでpretty-printします。これでホワイトスペースと改行が正規化され、Windows CRLFファイル対Unix LFファイルのような書式ノイズではなく、本当の内容変更にdiffが集中できます。ドキュメントが綺麗に解析されると、検証バッジが緑になります。

  3. 3

    diffを読む

    削除は左に赤いハイライトで、挿入は右に緑のハイライトで表示されます。各ヘッダーの変更カウントは、タグ名・属性値・可視テキストにわたってdiffが見つけた異なる編集の数を示します。どちらかのペインをスクロールすると、もう一方も連動して動きます。

HTML diffが正解になる場面

サーバーレンダリングされた2つのテンプレート出力を比較

CMSテンプレートの変更が出ると、下流の利用者からheroマークアップが壊れたと報告が来ます。デプロイ前後でレンダリング済みHTMLをcurlし、両方をdiffに貼り付けると、問題のラッパー<div>やクラスの入れ替わりが明らかになります。WordPressテーマのアップグレード、HugoやJekyllのレイアウト編集、ソーステンプレートが直接読めないあらゆるサーバーレンダリング出力で有用です。

A/Bテスト前にメールテンプレートのHTMLをdiff

メールHTMLは容赦ありません。OutlookはいまだにWordのレンダリングエンジンを使うので、<table>のネストの入れ替わりやインラインのstyle属性の改名でレイアウトが壊れます。キャンペーンを送信する前にバリアントAとBをdiffして、その後LitmusやEmail on Acidに通します。cellpadding="0"の欠落をdiffで捕まえるほうが、千の受信トレイで捕まえるより安上がりです。

PRのアクセシビリティ属性変更をレビュー

PRがコンポーネントの半分にaria-labelrolearia-describedby属性を追加します。テキストdiffがあれば、各インタラクティブ要素が正しい属性を得たこと、本物のボタンにrole="presentation"が当たっていないこと、フォーカス可能な要素がアクセシブル名を失っていないことを瑣末に確認できます。実監査にはaxe DevToolsやLighthouseを併用してください。

コピー修正後のマーケティングランディングページを比較

コピーライターから見出しを修正し新しいCTAを加えたホームページが返ってきます。本番のHTMLに対し提案HTMLを貼り付けると、どの<h1><p>、ボタンテキストが変わったか、それに混入したクラスやhrefの編集も含めてdiffが正確に教えてくれます。Wordの変更履歴より速く、コードベースへの往復にも耐えます。

HTMLサニタイザの出力をXSSリグレッションで監査

DOMPurifyやsanitize-htmlのバージョン更新後、既知の悪意あるペイロードでサニタイザの回帰テストを行い、出力を以前の良好なベースラインとdiffします。href属性の<svg onload="...">javascript: URLが突然保持されるサニタイザは、まさに本番に出る前にCIで捕まえたい類の回帰です。1文字の変更(エスケープの欠落)もdiffなら飛び出して見えます。

HTMLクイックリファレンス

このツールが最も頻繁に表面化させる解析の詳細について、短いチートシートです。すべてWHATWG HTML Living Standardに基づいています。

TopicWhat this tool does
void要素<img><br><input><meta><link><hr>とその仲間には閉じタグがありません。XHTMLスタイルの末尾スラッシュ<br />はHTML5で許容されますが、no-opとして描画され、parserは無視します。
属性順HTML specによれば意味を持ちません。<a href="/x" class="btn"><a class="btn" href="/x">はparserにとって同じです。テキストdiffは入れ替えを表示するので、両側を整形して順序を安定させてください。
属性のクオートスペースや特殊文字を含まない値には、ダブル、シングル、またはクオートなしのいずれも可能です。id=heroid='hero'id="hero"は等価です。多くのスタイルガイドは一貫性のためダブルクオートを要求します。
boolean属性存在することが意味を持ちます。<input disabled><input disabled=""><input disabled="disabled">はすべてinputを無効化します。specは裸の形を推奨し、XHTMLは冗長な形を要求しました。
大文字小文字の区別HTMLではタグ名と属性名は大文字小文字を区別しません(<DIV><div>は同じ)。属性値は区別します(id="Hero"id="hero"は異なる)。HTML5以降の慣習はタグと属性を小文字にすることです。
文字エンティティ組み込みは5つ:&amp; &lt; &gt; &quot; &apos;。さらに&nbsp;のような名前付きエンティティ、アクセント付き文字に対する&#233;のような数値参照があります。CDATAセクションは外部コンテンツ(SVG、MathML)でのみ有効で、通常のHTMLでは使えません。
DOCTYPEHTML5は短縮形<!DOCTYPE html>を使います。古いXHTML 1.0のdoctypeは依然として解析されますが、同じようにno-quirksモードを引き起こします。DOCTYPEが欠落または不正だと、ページがquirksモードに落ちて、boxモデルの挙動が変わります。
ホワイトスペーススペース・タブ・改行の連続は描画時に1つのスペースに畳み込まれます。ただし<pre><textarea>、CSS white-space: preを持つ要素の中は除きます。ソーステキストは保持されるので、テキストdiffはすべてのバイトを見ます。

HTML diff: よくある質問

markupにはプレーンテキストではなくHTML diffビューを使うべき理由は?

内部では同じ文字レベルのアルゴリズムですが、エディタはHTMLモードのハイライトを使うので、diffを読みながらタグ・属性・エンティティが馴染みのシンタックス色で表示されます。FormatボタンはHTML対応のpretty-printerを使い、汎用のテキスト整形ではないので、要素のネストが保たれます。マークアップなしの文章なら普通のテキストdiffで十分です。タグの境界が重要なファイルなら、このビューのほうがスキャンしやすいです。

要素の属性順は重要ですか?

ブラウザにとっては重要ではありません。HTML Living Standardは開始タグ上の属性順は意味を持たないと述べているので、<a href="/x" class="btn"><a class="btn" href="/x">は同じように描画されます。テキストdiffは生の文字を見るので、それでも入れ替えを表示します。対処法はdiff前に同じツール(Prettierやhtml-validateは妥当に並び替えます)で両側を整形することで、属性順を安定させることです。

要素間のホワイトスペースがdiffに出るのはなぜ?

HTMLは描画時にほとんどのホワイトスペース連続を1つのスペースに畳み込むので、ブラウザでは同じに見える2つのファイルでもソーステキストが大きく異なることがあります。<pre><textarea>の中ではホワイトスペースは保持されます。diffはテキストレベルなので、すべてのスペース、タブ、改行が数えられます。先に両側を整形してインデントを正規化してください。意味のある変更だけがハイライトされたまま残ります。

書式を無視してDOM構造を比較できますか?

このツールはテキストdiffであってDOM diffではないので、書式ノイズを無視する最も確実な方法は、貼り付け前に同じpretty-printer(Prettier、HTML Tidy、htmlhint --format)で両側を整形することです。それでインデント、属性のクオート、行末のホワイトスペースが正規化されます。本当のツリーレベル比較が要るなら、各側をDOMParserで解析してノードを歩いてください。コードレビューやコピー修正作業には、整形してからdiffするフローのほうが速く、同じバグを捕まえます。

インラインJavaScriptとCSSはどう扱われますか?

<script><style>の中身はプレーンテキストとして1文字ずつdiffされます。つまり、<style>ブロック内の1行のCSS変更や、インライン<script>内で改名された関数は、期待どおりの場所で表示されます。大きめのスクリプトブロックは.jsファイルに切り出して別途diffすることを検討してください。エディタのHTMLモードはそれでもscriptとstyleの境界をハイライトするので、周りのマークアップは読みやすいままです。

文字エンコーディングとエンティティについては?

ファイルはUTF-8として読み込まれます。これはHTML5の既定であり、<meta charset="UTF-8">タグが宣言するものです。&amp;&lt;&gt;&nbsp;のような名前付きエンティティはデコードされた形ではなくリテラルなソーステキストとしてdiffされるので、&nbsp;から実際のスペース文字への入れ替えは変更として表示されます。2つのファイルがブラウザで同じに描画されるのにdiffが先頭で光るなら、片方のUTF-8 byte order markを疑ってください。

プライバシーと仕組み

あなたのHTMLはブラウザから出ません。フォーマッタ、検証、diffはすべてあなたのマシン上、ローカルで動作します。入力に対する解析、ログ、「親切な」クラウドへの往復はありません。シンタックスハイライトはWHATWG HTML Living Standardに従い、より古いW3C HTML 5.2勧告も有用なクロスリファレンスです。要素単位のリファレンスドキュメントはMDNにあり、アクセシビリティパターンはARIA Authoring Practices Guideから来ています。フォーマット自体の背景はWikipediaにあります。