마크다운 ID, 왜 숫자로 시작하면 작동하지 않을까?

부제: 마크다운 파서의 자동 생성과 수동 지정의 비밀 파헤치기

마크다운(Markdown)으로 문서를 작성하다 보면 특정 섹션으로 바로 이동할 수 있는 링크를 만들기 위해 헤더(Header)에 ID를 직접 지정하곤 합니다. 보통은 아래와 같이 잘 작동하죠.

### 아주 멋진 제목 {#my-awesome-title}

...

[위 제목으로 이동하기](#my-awesome-title)

그런데 이런 경우는 어떨까요? 1장을 의미하기 위해 ID를 1-section으로 지정하고 싶습니다.

### 1장. 시작하며 {#1-section}

왠지 모르게 이 ID는 작동하지 않거나, 링크가 깨지는 답답한 경험을 하신 적이 있나요? 이것은 버그가 아닙니다. 마크다운을 처리하는 파서(parser)의 의도된 설계에 가깝습니다.

이 글에서는 왜 숫자로 시작하는 마크다운 ID가 문제를 일으키는지, 그리고 이 문제를 해결하는 가장 좋은 방법은 무엇인지 명쾌하게 알려드립니다.

모든 문제의 근원: CSS와의 충돌

이 문제의 근본적인 원인은 마크다운 자체가 아닌, 마크다운이 최종적으로 변환되는 HTML과 CSS의 관계에 있습니다.

  1. HTML 표준: 과거 HTML4에서는 ID가 숫자로 시작할 수 없었습니다. HTML5에서는 이 규칙이 완화되어 문법적으로는 id="1-section"이 유효합니다.
  2. CSS 선택자의 한계: 진짜 문제는 CSS에 있습니다. CSS는 ID를 선택하기 위해 # 기호를 사용합니다. 예를 들어 id="my-id"는 CSS에서 #my-id로 선택합니다. 하지만 ID가 1-section이라면 어떻게 될까요? CSS 파서는 #1-section을 ID로 인식하지 못하고, # 다음에 오는 1을 다른 의미의 숫자 값으로 해석하려고 시도하면서 선택자(Selector)가 깨져버립니다.

이러한 잠재적인 문제를 피하기 위해, 대부분의 마크다운 파서는 사용자가 직접 지정하는 ID가 숫자로 시작하는 것을 의도적으로 막거나, 허용하지 않는 것입니다. 일종의 ‘안전장치’인 셈이죠.

“그런데 왜 ### 1. 제목은 자동으로 ID를 만들까요?”

여기서 많은 분이 혼란을 겪습니다. 분명 아래와 같이 작성하면,

### 1. 시작하며

파서는 자동으로 <h3 id="1-시작하며"> 와 같이 숫자로 시작하는 ID를 잘만 만들어 줍니다. 왜 이런 차이가 발생하는 걸까요?

핵심은 ‘자동 생성’‘수동 지정’을 파서가 다르게 취급하기 때문입니다.

구분 자동 생성 ID (### 1. 시작하며) 수동 지정 ID ({#1-section})
제어 주체 마크다운 파서가 내부 규칙에 따라 생성 사용자가 특정 ID를 강제로 지정
적용 규칙 파서가 스스로 제어할 수 있어 유연함 외부 입력이라 더 엄격한 유효성 검사 적용
목적 일관성 있는 문서 구조 자동화 특정 목적을 위한 ID 강제
결과 id="1-시작하며" 생성 가능 id="1-section" 생성 차단

즉, 파서는 자신이 직접 만드는 ID는 시스템 내에서 문제없이 처리할 수 있다고 확신하지만, 사용자가 직접 입력한 ID는 외부(CSS, JavaScript)에서 문제를 일으킬 수 있으니 가장 안전한 규칙(문자로 시작)을 강제하는 것입니다.

해결책: 어떻게 해야 할까?

이제 원인을 알았으니 해결책을 찾아봅시다.

방법 1: 문자로 시작하기 (가장 권장되는 방법)

가장 간단하고 확실하며, 모든 환경에서 호환되는 방법입니다. ID 앞에 의미 있는 접두사(prefix)를 붙여주세요.

### 1장. 시작하며 {#ch-1}

### 섹션 1. 개요 {#sec-1-summary}

ch(chapter), sec(section), h(header) 등 어떤 문자든 좋습니다. 이렇게 하면 CSS나 JavaScript에서 ID를 참조할 때 아무런 문제를 겪지 않을 것입니다.

방법 2: HTML 직접 사용하기 (가장 확실한 해결책)

“저는 반드시 id="1-section"을 사용해야만 합니다!” 라고 하는 특별한 경우가 있을 수 있습니다. 마크다운 문법으로는 불가능하지만, 마크다운은 HTML과 함께 사용할 수 있다는 장점이 있습니다.

ID를 지정하고 싶은 부분만 직접 HTML 태그로 작성하면 파서의 제약을 완전히 우회할 수 있습니다.

<h3 id="1-section">1장. 시작하며</h3>

이 방법은 여러분이 원하는 ID를 100% 보장하는 가장 확실한 해결책입니다.

결론: 핵심 요약

  • 마크다운에서 {#1-my-id}처럼 수동으로 ID를 지정할 때 숫자로 시작하면 작동하지 않는 것은 CSS와의 호환성을 위한 파서의 안전장치 때문입니다.
  • 파서가 자동으로 생성하는 ID (### 1. 제목의 경우)는 파서가 제어할 수 있기 때문에 숫자로 시작할 수 있습니다.
  • 가장 좋은 해결책{#ch-1}과 같이 항상 문자 접두사를 붙여주는 것입니다.
  • 꼭 숫자로 시작하는 ID를 써야 한다면, 해당 부분만 직접 HTML 태그를 사용하세요.

이제 마크다운 ID의 비밀을 알게 되셨으니, 더 이상 링크가 깨질 걱정 없이 자유롭게 문서를 구조화하실 수 있을 겁니다.