깔끔한 코드를 위한 HTML 포맷팅 모범 사례
파일을 열었는데, 들여쓰기 하나 없이 태그가 다닥다닥 붙어 있고, div로 뒤덮인 수백 줄의 HTML이 눈앞에 펼쳐집니다. 빠진 닫는 태그를 찾는 것은 불가능에 가깝습니다. 누구나 한 번쯤은 겪어 본 고통이며, 올바른 HTML 포맷팅은 이런 고통을 완전히 해소해 줍니다.
잘 정돈된 HTML은 단순히 보기 좋은 것 이상의 의미가 있습니다. 버그를 얼마나 빨리 디버깅할 수 있는지, 팀원과의 협업이 얼마나 원활한지, 그리고 코드가 시간이 지나도 얼마나 유지보수하기 쉬운지에 직접적인 영향을 줍니다. 간단한 랜딩 페이지를 만들든 복잡한 웹 애플리케이션을 개발하든, 포맷팅 습관은 이후의 모든 작업에 영향을 미칩니다.
잘 정돈된 HTML이 중요한 이유
가독성
코드는 작성되는 것보다 읽히는 횟수가 훨씬 더 많습니다. HTML이 일관된 포맷팅 규칙을 따르면, 팀의 누구든 한눈에 구조를 파악할 수 있습니다. 중첩된 요소가 명확하게 드러나고, 빠진 태그가 눈에 띄며, 전체 문서 흐름이 명확해집니다.
유지보수
6개월 후에 그 컴포넌트를 수정해야 할 때가 옵니다. 깔끔한 포맷팅이 되어 있으면 바로 들어가서 수정하고 다음 작업으로 넘어갈 수 있습니다. 구조를 파악하는 데만 처음 20분을 허비하는 일은 없어집니다.
협업
팀 전체가 같은 포맷팅 규칙을 따르면, 코드 리뷰가 공백에 대한 논쟁이 아닌 로직과 아키텍처에 대한 생산적인 대화가 됩니다. 포맷팅이 일관되면 병합 충돌도 줄어듭니다.
디버깅
잘 들여쓰기된 HTML 문서는 계층 구조를 즉시 드러냅니다. 무언가가 잘못 렌더링될 때, 중첩 관계를 시각적으로 추적하여 문제를 찾을 수 있습니다. 축소되거나 포맷이 엉망인 마크업은 이런 구조적 관계를 숨깁니다.
들여쓰기 스타일과 규칙
HTML에서의 들여쓰기 논쟁은 프로그래밍 커뮤니티 전반의 논쟁과 크게 다르지 않습니다: 스페이스냐 탭이냐, 그리고 한 레벨당 몇 칸이냐 하는 것입니다.
2칸 스페이스
2칸 들여쓰기는 HTML에서 가장 인기 있는 선택이며, Google 스타일 가이드, Prettier의 기본 설정, 그리고 대부분의 최신 프론트엔드 프레임워크에서 사용됩니다.
<main>
<section>
<h1>Welcome</h1>
<p>This is a paragraph.</p>
</section>
</main>
장점은 명확한 계층 구조를 보여주면서도 코드가 간결하다는 것입니다. 깊게 중첩된 HTML — 이는 자주 발생합니다 — 에서 2칸 스페이스는 줄이 오른쪽으로 너무 밀려나는 것을 방지합니다.
4칸 스페이스
4칸 들여쓰기는 중첩 레벨 간에 더 넓은 시각적 간격을 제공하여 계층 구조를 더욱 뚜렷하게 만듭니다.
<main>
<section>
<h1>Welcome</h1>
<p>This is a paragraph.</p>
</section>
</main>
중첩이 얕은 HTML 템플릿에서 이를 선호하는 팀도 있습니다. 그러나 여러 레벨의 중첩이 있는 복잡한 레이아웃에서는 코드가 화면 오른쪽으로 불편하게 밀려날 수 있습니다.
탭
탭을 사용하면 각 개발자가 에디터에서 원하는 시각적 너비를 설정할 수 있습니다. 실제 파일 내용은 변경하지 않으면서, 한 개발자에게는 2칸으로, 다른 개발자에게는 4칸으로 표시될 수 있습니다.
하나를 선택하고 일관성을 유지하세요
어떤 것을 선택하느냐보다 일관성이 훨씬 더 중요합니다. 에디터를 설정하고, Prettier 같은 포맷터를 구성하고, pre-commit 훅으로 적용하세요. 들여쓰기 스타일에 대한 논쟁은 규칙을 정할 때 한 번만 하면 됩니다. 매번 풀 리퀘스트마다 할 필요가 없습니다.
시맨틱 HTML5 요소
시맨틱 요소는 브라우저와 보조 기술 모두에 의미를 전달합니다. 범용 div와 span을 콘텐츠 역할을 설명하는 전용 태그로 대체합니다.
문서 구조 요소
<body>
<header>
<nav>
<a href="/">Home</a>
<a href="https://example.com/about">About</a>
</nav>
</header>
<main>
<article>
<h1>Article Title</h1>
<p>Article content goes here.</p>
<section>
<h2>Subsection</h2>
<p>More detailed content.</p>
</section>
</article>
<aside>
<h2>Related Links</h2>
<ul>
<li><a href="https://example.com/related">Related Article</a></li>
</ul>
</aside>
</main>
<footer>
<p>© 2026 Example Inc.</p>
</footer>
</body>
각 요소의 사용 시기
<header>— 도입 콘텐츠 또는 네비게이션 링크. 페이지 레벨뿐만 아니라<article>이나<section>안에서도 사용할 수 있습니다.<nav>— 주요 네비게이션 블록. 모든 링크 그룹에 사용하지 말고, 주요 네비게이션에만 사용하세요.<main>— 페이지의 핵심 콘텐츠. 페이지당 하나만 사용할 수 있으며,<article>,<aside>,<header>,<footer>,<nav>안에 중첩해서는 안 됩니다.<article>— 그 자체로 의미가 완결되는 독립적 콘텐츠: 블로그 글, 뉴스 기사, 포럼 게시글, 제품 카드.<section>— 보통 제목을 동반하는 주제별 콘텐츠 그룹. 콘텐츠가 논리적 섹션을 나타낼 때div대신 사용하세요.<aside>— 주변 콘텐츠와 간접적으로 관련된 콘텐츠: 사이드바, 인용문, 관련 링크.<footer>— 가장 가까운 섹션 조상의 푸터 정보.<header>처럼 아티클이나 섹션 안에서도 사용할 수 있습니다.
div와 시맨틱 요소의 차이
div는 의미론적 의미가 없습니다. 스타일링과 레이아웃을 위한 범용 컨테이너일 뿐입니다. div를 사용하려 할 때 스스로에게 물어보세요: 시맨틱 요소가 이 콘텐츠를 더 잘 설명하는가? 그렇다면 시맨틱 요소를 대신 사용하세요.
<!-- Avoid this -->
<div class="navigation">
<div class="nav-links">
<a href="/">Home</a>
</div>
</div>
<!-- Prefer this -->
<nav>
<a href="/">Home</a>
</nav>
접근성 패턴
접근성 있는 HTML은 별도의 관심사가 아닙니다 — 잘 작성된 HTML 그 자체입니다. 대부분의 접근성 개선은 마크업을 더 깔끔하고 의미 있게 만들어 줍니다.
제목 계층 구조
제목은 논리적 순서를 따라야 합니다. 스타일링 목적으로 레벨을 건너뛰지 마세요 — 시각적 크기 조절에는 CSS를 사용하세요.
<!-- Correct hierarchy -->
<h1>Page Title</h1>
<h2>Major Section</h2>
<h3>Subsection</h3>
<h3>Another Subsection</h3>
<h2>Another Major Section</h2>
<!-- Incorrect — skips h2 -->
<h1>Page Title</h1>
<h3>This skips a level</h3>
이미지 대체 텍스트
모든 <img> 요소에는 alt 속성이 필요합니다. 설명적인 대체 텍스트는 스크린 리더 사용자가 콘텐츠를 이해하는 데 도움을 줍니다. 장식용 이미지의 경우 빈 alt=""를 사용하여 해당 이미지가 정보를 전달하지 않음을 나타내세요.
<!-- Informative image -->
<img src="chart.png" alt="Bar chart showing revenue growth from Q1 to Q4 2025">
<!-- Decorative image -->
<img src="decorative-border.png" alt="">
폼 레이블
모든 폼 입력 필드에는 연결된 레이블이 있어야 합니다. 레이블의 for 속성은 입력 필드의 id와 일치해야 합니다.
<label for="email">Email Address</label>
<input type="email" id="email" name="email" required>
플레이스홀더 텍스트를 레이블 대신 사용하지 마세요. 플레이스홀더는 사용자가 입력을 시작하면 사라지므로, 해당 필드가 무엇을 기대하는지에 대한 맥락이 제거됩니다.
ARIA 레이블
네이티브 HTML 시맨틱이 불충분할 때 ARIA 속성을 사용하세요. 하지만 ARIA의 첫 번째 규칙은: 필요한 시맨틱을 이미 가진 네이티브 HTML 요소를 사용할 수 있다면, 그것을 먼저 사용하라는 것입니다.
<!-- ARIA for custom components -->
<button aria-label="Close dialog" aria-expanded="false">
<svg><!-- icon --></svg>
</button>
<!-- Better: use native semantics when possible -->
<button type="button">Close</button>
키보드 네비게이션
인터랙티브 요소는 키보드로 접근 가능해야 합니다. <button>, <a>, <input> 같은 네이티브 HTML 요소는 기본적으로 키보드 접근이 가능합니다. 인터랙티브 요소에 div나 span을 사용할 때(일반적으로 피해야 하지만), tabindex="0"과 키보드 이벤트 핸들러를 추가하세요.
속성 순서 규칙
일관된 속성 순서는 HTML을 더 쉽게 훑어볼 수 있게 만듭니다. 엄격한 표준은 없지만, 널리 채택된 규칙은 중요도와 기능별로 속성을 정렬합니다:
<input
type="email"
id="user-email"
name="email"
class="form-input"
placeholder="you@example.com"
required
aria-describedby="email-help"
data-validate="email"
>
권장 순서:
type— 요소 또는 입력 필드의 종류id— 고유 식별자name— 폼 제출 이름class— 스타일링 훅src,href,for— 리소스 참조value,placeholder— 콘텐츠 속성required,disabled,checked— 불리언 상태aria-*— 접근성 속성data-*— 커스텀 데이터 속성
이것은 절대적인 규칙이 아니지만, 프로젝트 내에서의 일관성이 중요합니다. 린터를 설정하여 선택한 순서를 적용하세요.
셀프 클로징 태그, 빈 요소, 불리언 속성
빈 요소
일부 HTML 요소는 콘텐츠를 가질 수 없으며 닫는 태그가 필요하지 않습니다. 이를 빈 요소(void elements)라고 합니다:
<br>
<hr>
<img src="photo.jpg" alt="A sunset over the ocean">
<input type="text" name="search">
<meta charset="utf-8">
<link rel="stylesheet" href="styles.css">
HTML5에서는 빈 요소를 슬래시로 닫을(<br />) 필요가 없습니다. 슬래시는 선택 사항이며 순전히 스타일적입니다. 하지만 프로젝트가 JSX나 XHTML을 사용한다면 셀프 클로징 문법이 필요합니다.
불리언 속성
불리언 속성은 존재하거나 존재하지 않는 것이며, 값이 필요하지 않습니다. 속성이 있으면 true를 의미하고, 없으면 false를 의미합니다.
<!-- These are equivalent -->
<input type="text" required>
<input type="text" required="required">
<input type="text" required="">
<!-- Preferred: just the attribute name -->
<input type="text" required>
<button disabled>Submit</button>
<video autoplay muted></video>
흔한 HTML 포맷팅 실수
1. 일관되지 않은 들여쓰기
탭과 스페이스를 혼용하거나 레벨별 스페이스 수가 달라지면 시각적 혼란이 생깁니다. 포맷터를 사용해 이를 방지하세요.
2. Div 남용
시맨틱 요소가 의미를 더 잘 전달할 수 있는 곳에 모든 것을 div로 감싸는 것입니다. 이는 접근성, SEO, 코드 가독성을 저해합니다.
<!-- Div soup -->
<div class="header">
<div class="nav">
<div class="nav-item"><a href="/">Home</a></div>
</div>
</div>
<!-- Clean semantic markup -->
<header>
<nav>
<a href="/">Home</a>
</nav>
</header>
3. Alt 속성 누락
이미지에서 alt를 생략하는 것은 접근성 위반이며 모든 HTML 유효성 검사기에서 경고를 발생시킵니다.
4. 인라인 스타일
HTML 곳곳에 style 속성을 뿌리면 관심사가 혼합되고 유지보수가 어려워집니다. 대신 CSS 클래스를 사용하세요.
5. 지나치게 깊은 중첩 구조
HTML이 6~7단계까지 깊어진다면 레이아웃을 다시 생각해 보세요. 깊은 중첩은 보통 더 나은 컴포넌트 아키텍처로 구조를 단순화할 수 있음을 나타냅니다.
6. 문서 언어 누락
항상 <html> 요소에 lang 속성을 포함하세요. 스크린 리더는 이를 사용하여 올바른 발음 규칙을 선택합니다.
<html lang="en">
7. <!DOCTYPE html> 선언 미사용
항상 HTML 문서를 doctype 선언으로 시작하세요. 이것이 없으면 브라우저가 쿼크 모드로 페이지를 렌더링하여 일관되지 않은 동작을 유발할 수 있습니다.
자동화된 코드 정리 및 린팅 도구
수동 포맷팅은 오류가 발생하기 쉽고 지루합니다. 자동화 도구는 지속적인 노력 없이 일관성을 유지합니다.
Prettier
Prettier는 웹 개발에서 가장 인기 있는 코드 포맷터입니다. HTML, CSS, JavaScript 및 기타 다양한 언어를 지원합니다. 한 번 설정하면 들여쓰기, 속성 줄바꿈, 줄 길이를 자동으로 처리합니다.
{
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"htmlWhitespaceSensitivity": "css"
}
에디터에서 저장 시 또는 pre-commit 훅으로 Prettier를 실행하면, 포맷팅이 완전히 자동화됩니다.
HTMLHint
HTMLHint는 HTML 전용 정적 분석 도구입니다. 포맷터가 잡지 못하는 문제 — alt 속성 누락, 중복 ID, 폐기된 요소 등 — 을 감지합니다.
{
"tagname-lowercase": true,
"attr-lowercase": true,
"attr-value-double-quotes": true,
"tag-pair": true,
"id-unique": true,
"alt-require": true
}
에디터 통합
대부분의 최신 에디터 — VS Code, WebStorm, Sublime Text — 는 내장 또는 플러그인 기반의 HTML 포맷팅 기능을 갖추고 있습니다. 저장 시 자동 포맷을 활성화하여 별도의 신경 없이 HTML을 깔끔하게 유지하세요.
프로덕션용 축소(Minification)
개발용 HTML은 아름답게 포맷팅되어야 하지만, 프로덕션 HTML은 파일 크기를 줄이기 위해 축소의 이점을 누릴 수 있습니다. Code Minifier를 사용하면 공백을 제거하고, 주석을 삭제하고, 배포를 위해 HTML을 압축할 수 있습니다. 핵심은 소스 코드는 포맷팅된 상태로 유지하고 출력만 축소하는 것입니다.
도구 및 리소스
올바른 도구가 있으면 좋은 포맷팅 습관을 더 쉽게 유지할 수 있습니다:
- Code Minifier — 소스 코드를 깔끔하게 유지하면서 프로덕션용으로 HTML, CSS, JavaScript를 축소
- Markdown Previewer — HTML 출력을 자주 생성하는 Markdown 콘텐츠를 미리 보고 포맷팅
자주 묻는 질문
HTML 들여쓰기에 2칸과 4칸 중 무엇을 사용해야 하나요?
2칸이 현대 웹 개발에서 가장 일반적인 규칙이며 Prettier의 기본값입니다. 4칸은 중첩이 얕은 간단한 문서에 적합합니다. 가장 중요한 것은 하나를 선택하고 포맷터로 적용하는 것입니다.
시맨틱 HTML과 일반 HTML의 차이는 무엇인가요?
시맨틱 HTML은 범용 컨테이너(<div>, <span>) 대신 콘텐츠의 의미를 설명하는 요소(<article>, <nav>, <header>)를 사용합니다. 시맨틱 마크업은 접근성, SEO, 코드 가독성을 향상시킵니다.
시맨틱 HTML을 사용하면 ARIA 속성이 필요 없나요?
대부분의 경우 시맨틱 HTML이 충분한 접근성 정보를 제공합니다. ARIA는 커스텀 드롭다운 메뉴나 탭 패널처럼 네이티브 HTML에 대응하는 요소가 없는 커스텀 인터랙티브 컴포넌트를 만들 때 필요합니다.
팀 전체에 HTML 포맷팅을 어떻게 적용하나요?
공유 설정 파일이 있는 Prettier를 사용하고, 린팅을 위한 HTMLHint 설정을 추가하고, Husky와 lint-staged 같은 도구를 사용하여 둘 다 pre-commit 훅으로 실행하세요.
<br />처럼 빈 요소를 셀프 클로징해도 괜찮나요?
HTML5에서 빈 요소의 후행 슬래시는 선택 사항입니다. <br>과 <br /> 모두 유효합니다. JSX(React)에서는 셀프 클로징 문법이 필수입니다. 프로젝트나 프레임워크가 기대하는 규칙을 따르세요.
관련 리소스
- Code Minification Guide — 프로덕션을 위해 HTML, CSS, JavaScript를 압축하는 방법 알아보기
- Markdown Syntax Guide — 문서화와 콘텐츠를 위한 Markdown 포맷팅 마스터하기
- HTML Entities Encoding Guide — HTML에서 특수 문자를 올바르게 처리하기
🛠️ 지금 사용해 보세요: Code Minifier — 포맷팅된 HTML을 프로덕션용으로 축소합니다. 100% 무료, 모든 처리가 브라우저에서 이루어집니다. 데이터 업로드 없음.