두 HTML 파일의 차이점 찾는 방법

두 HTML 파일은 브라우저에서 동일하게 렌더링될 수 있지만 소스 코드에서는 수십 곳이 다를 수 있습니다. 태그 주변의 공백, 속성 순서, HTML 엔티티, 자기 닫힘 구문이 주요 원인입니다. 일반 텍스트 diff는 이들 모두를 변경 사항으로 표시하여 실제로 중요한 내용을 가려 버립니다. 이 가이드는 깔끔한 결과를 얻는 방법을 보여줍니다.

도구로 바로 넘어가고 싶다면, HTML 비교 페이지에서 두 파일을 붙여넣기 하고 브라우저에서 diff를 확인할 수 있습니다. 설치가 필요 없습니다. 나머지 글에서는 결과를 확인할 때 무엇을 살펴봐야 하는지 설명합니다.

HTML diff가 많은 노이즈를 만드는 이유

HTML은 줄 단위 형식이 아닙니다. 단락이 한 줄의 긴 줄 또는 열 줄에 걸쳐 작성될 수 있으며 둘 다 유효합니다. 대부분의 편집기, 코드 포매터, CMS는 저장 시 HTML을 재형식화하므로 단어 하나가 변경되어도 수십 줄의 재형식화된 줄로 이어질 수 있습니다. diff는 이를 "단어 하나가 변경됨"이 아닌 변경된 줄로 인식합니다.

WHATWG HTML Living Standard는 브라우저가 HTML을 파싱하는 방법을 규정하지만 텍스트로 직렬화하는 방법은 규정하지 않습니다. 두 도구는 구조적으로 동일한 HTML을 생성하지만 원시 텍스트로는 전혀 다르게 보일 수 있습니다.

노이즈의 대부분을 차지하는 네 가지 요인:

  • 공백 태그 사이와 내부
  • 속성 순서 (브라우저는 특정 순서를 요구하지 않음)
  • HTML 엔티티 vs 리터럴 문자
  • 빈 요소 구문 (<br> vs <br />)

공백: 거짓 양성의 가장 큰 원인

대부분의 상황에서 HTML의 연속된 공백은 브라우저가 렌더링할 때 단일 공백으로 축소됩니다. 즉, 이 두 스니펫은 동일하게 표시됩니다:

<!-- Version 1 -->
<p>Free text comparison tool.</p>

<!-- Version 2 -->
<p>
  Free text comparison tool.
</p>

일반 텍스트 diff는 두 줄 모두 변경된 것으로 표시합니다. 실제로는 의미 있는 측면에서 변경되지 않았습니다. 비교하기 전에 사용 사례에서 공백이 중요한지 결정하세요. 이메일 템플릿이나 PDF 렌더러에서는 중요할 때가 있습니다. 대부분의 웹 페이지에서는 중요하지 않습니다.

최선의 해결책은 diff를 실행하기 전에 동일한 설정으로 Prettier와 같은 포매터를 통해 두 파일을 처리하는 것입니다. 이렇게 하면 들여쓰기, 줄 길이, 간격을 한 번에 정규화할 수 있습니다. 두 파일이 동일한 형식 스타일을 공유하면 일반 텍스트 diff는 실제 콘텐츠 변경 사항만 표시합니다.

속성 순서

HTML 사양은 속성이 특정 순서로 나타나도록 요구하지 않습니다. <div id="main" class="container"><div class="container" id="main">는 같은 요소입니다. 하지만 줄 단위 diff는 이들을 다른 줄로 처리합니다. 이는 특히 템플릿이 다른 도구에 의해 생성되거나 누군가가 속성을 알파벳 순으로 정렬하는 자동 포매터를 실행한 경우에 흔히 발생합니다.

WHATWG 파싱 사양에 따르면 같은 요소의 속성은 정의상 순서가 없습니다. 속성 순서 변경을 변경 사항으로 보고하는 diff는 기술적으로는 맞지만 거의 유용하지 않습니다. 이것이 노이즈를 일으키고 있다면 비교하기 전에 두 파일의 속성 순서를 정규화하세요.

HTML 엔티티

&amp;, &lt;, &gt;, &nbsp;, &#8212; 같은 숫자 참조 — 이들은 모두 HTML 소스에서 문자를 인코딩하는 방법입니다. 두 파일이 같은 문자를 다르게 인코딩해도 같은 페이지를 렌더링할 수 있습니다. 텍스트 diff는 &amp;&를 다른 문자열로 보지만, 둘 다 브라우저에서 앰퍼샌드를 생성합니다.

엔티티 차이가 diff를 어지럽히고 있다면 비교하기 전에 엔티티를 정규화하는 HTML 파서를 통해 두 파일을 처리하세요. 브라우저 자체의 DOMParser API는 JavaScript에서 이를 수행하는 신뢰할 수 있는 방법입니다: 두 문자열을 파싱하고 innerHTML로 직렬화한 다음 결과를 diff하세요.

빈 요소

HTML5에서 빈 요소(자식이 없는 요소)는 닫는 슬래시가 필요하지 않습니다. <br>, <br/>, <br />는 모두 유효하며 동일하게 파싱됩니다. <img>, <input>, <meta> 등도 마찬가지입니다. 한 파일이 XHTML 스타일의 자기 닫힘 슬래시를 사용하고 다른 파일이 순수 HTML5 구문을 사용한다면 텍스트 diff는 해당 요소들을 모두 표시합니다.

MDN의 빈 요소 전체 목록에는 14개가 모두 포함되어 있습니다. diff 결과에서 />를 빠르게 검색하면 노이즈의 얼마나 많은 부분이 자기 닫힘 구문에서 비롯되는지 알 수 있습니다.

실제 예제

사이트 헤더에 대한 현실적인 변경 전후 예제입니다. 세 가지가 변경되었습니다: 헤더에 CSS 클래스가 추가되고, 홈 링크 대상이 수정되고, 연락처 링크가 추가되었습니다.

<!-- Version 1 -->
<header class="site-header">
  <nav>
    <a href="/home" class="nav-link active">Home</a>
    <a href="/about" class="nav-link">About</a>
  </nav>
</header>

<!-- Version 2 -->
<header class="site-header sticky-top">
  <nav>
    <a href="/" class="nav-link active">Home</a>
    <a href="/about" class="nav-link">About</a>
    <a href="/contact" class="nav-link">Contact</a>
  </nav>
</header>

두 파일을 HTML 비교 도구에 붙여넣으면 diff는 정확히 세 줄을 강조합니다: 헤더 class 속성, 홈 href, 새 앵커 태그. 두 버전 간에 들여쓰기와 형식이 일관되어 노이즈가 없습니다.

위 예제에서 변경된 내용
요소 버전 1 버전 2 변경 유형
<header> class="site-header" class="site-header sticky-top" 클래스 추가됨
홈 링크 href="/home" href="/" 경로 수정됨
연락처 링크 없음 <a href="/contact">Contact</a> 추가됨

비교 전에 정규화해야 할 때

모든 HTML 비교가 정규화를 필요로 하는 것은 아닙니다. 동일한 편집기 설정으로 직접 작성한 두 파일을 비교하는 경우 일반 텍스트 diff로 충분합니다. 정규화가 효과적인 경우:

  • 한 파일이 CMS 내보내기에서 오고 다른 파일이 편집기에서 온 경우
  • 빌드 도구가 한 파일은 재형식화했지만 다른 파일은 하지 않은 경우
  • 최소화된 HTML을 예쁘게 출력된 HTML과 비교하는 경우
  • 외부 발신자의 HTML 이메일 템플릿을 검토하는 경우

W3C 마크업 유효성 검사 서비스는 비교하기 전에 두 파일이 올바르게 파싱되는지 확인하는 데 유용합니다. 태그 구조가 손상된 파일은 파서가 자체적인 방식으로 오류에서 복구하고 두 파서가 다르게 복구할 수 있으므로 오해를 일으키는 diff를 생성합니다.

생성된 HTML 비교

서버 렌더링 프레임워크(Angular, Next.js, Rails)는 HTML 출력에 타임스탬프, nonce 또는 무작위 식별자를 삽입하는 경우가 많습니다. 같은 페이지를 두 번 렌더링하면 콘텐츠가 동일해도 해당 줄에서 diff가 달라집니다. 생성된 HTML을 비교하는 경우 diff를 실행하기 전에 해당 필드를 제거하거나 정규화하세요.

이 사이트의 기본 diff 엔진은 Google의 diff-match-patch (Apache 2.0)로, 원시 텍스트에서 작동합니다. HTML을 파싱하지 않으므로 콘텐츠 차이와 함께 형식 차이도 표시합니다. 그래서 먼저 정규화하는 것이 중요합니다. 하지만 대부분의 경우 두 파일을 직접 붙여넣으면 몇 초 안에 충분히 유용한 결과를 얻을 수 있습니다. HTML이 올바른 XHTML인 경우 XML 비교 도구도 시도해 볼 가치가 있습니다. XML 인식 diff는 네임스페이스와 속성 순서를 올바르게 처리합니다.

자주 묻는 질문

한 줄만 변경했는데 HTML diff에 수백 개의 변경 사항이 표시되는 이유는 무엇인가요?
거의 항상 형식 변경이 원인입니다. 편집기나 빌드 도구가 저장 시 파일을 재형식화(들여쓰기 변경, 긴 줄 줄바꿈, 속성 순서 변경)한 경우 일반 텍스트 diff는 재형식화된 모든 줄을 변경 사항으로 봅니다. 먼저 두 파일을 동일한 포매터를 통해 처리한 다음 비교하세요. 실제 변경 사항만 남을 것입니다.
HTML에서 속성 순서가 중요한가요?
브라우저에게는 중요하지 않습니다. HTML Living Standard는 속성이 특정 순서로 나타나도록 요구하지 않으며, 브라우저는 순서에 상관없이 올바르게 파싱합니다. 일부 린터와 포매터는 스타일 규칙으로 속성을 알파벳 순으로 정렬하여 의미적으로 동일한 두 파일이 텍스트 diff에서 다르게 보일 수 있습니다. 속성 순서가 노이즈를 일으키고 있다면 비교 전에 동일한 포매터로 두 파일을 정규화하세요.
HTML 소스에서 &amp;amp;와 &의 차이점은 무엇인가요?
브라우저가 페이지를 렌더링할 때 둘 다 앰퍼샌드 문자를 생성합니다. HTML 소스에서 &amp;는 엔티티 인코딩된 형식이고 &는 리터럴 문자입니다. 기술적으로 속성 값의 &는 사양에 따라 &amp;로 인코딩되어야 하지만 브라우저는 둘 다 허용합니다. 텍스트 diff는 이들을 다른 문자열로 처리합니다. 엔티티 인코딩이 노이즈를 만들고 있다면 라이브러리나 브라우저의 DOMParser로 두 파일을 파싱하고 비교하기 전에 직렬화하세요.
최소화된 HTML을 예쁘게 출력된 HTML과 비교할 수 있나요?
예, 하지만 먼저 최소화된 파일을 예쁘게 출력해야 합니다. 최소화된 것과 예쁘게 출력된 것을 비교하면 최소화로 인해 포매터가 추가한 모든 공백이 제거되므로 거의 모든 줄이 변경된 것처럼 보이는 결과가 나옵니다. 최소화된 파일을 Prettier나 동등한 포매터를 통해 처리한 다음 비교하세요. 공백 노이즈 없이 의미 있는 변경 사항이 보일 것입니다.
특정 컴포넌트 같은 HTML 파일의 일부만 비교하려면 어떻게 하나요?
두 파일에서 관련 섹션을 추출하여 그 부분만 diff 도구에 붙여넣으세요. 예를 들어 내비게이션 컴포넌트의 변경 사항을 검토하는 경우 각 파일에서 <nav> 블록만 복사하세요. 한 섹션에만 관심이 있을 때 전체 문서를 비교하면 페이지의 관련 없는 부분에서 노이즈가 추가됩니다.
HTML 주석이 diff에 나타나나요?
예. 텍스트 기반 diff는 주석을 포함한 파일의 모든 내용을 포함합니다. 한 버전에 주석 블록이 있고 다른 버전에서 제거했거나 개발자가 주석을 업데이트했다면 diff에서 이를 보여줍니다. 이는 보통 유용합니다: 제거된 주석은 종종 의도적인 정리를 나타냅니다. 주석을 무시하려면 비교 전에 두 파일에서 주석을 제거하세요.

HTML 파일을 비교할 준비가 되셨나요? 두 파일을 무료 HTML 비교 도구에 붙여넣고 계정 없이 차이점을 나란히 확인하세요.