QSike Tech Notes

블로그 글에 갑자기 취소선이 생겼다면: 숫자 범위 표기부터 확인하세요

원고에서는 멀쩡한 숫자 범위가 발행 후 취소선으로 바뀐 실제 사례다. 글만 편집할 수 있을 때와 사이트 설정을 바꿀 수 있을 때의 해결법을 나누고, 게시 화면에서 확인할 내용을 정리했다.

원고에서는 멀쩡하던 문장에 발행 후 긴 가로줄이 그어졌다. 이 블로그에서는 장비 납기를 설명한 문단에 이런 일이 생겼다. 숫자 범위를 나타낸 물결표를 글 표시 도구가 취소선 문법으로 해석한 것이었다.

글을 직접 쓰든 AI의 도움을 받든, 원고가 맞는 것과 독자 화면이 맞는 것은 따로 확인해야 한다. 이 사례에서 바꾼 것은 숫자의 내용이 아니라 그 숫자를 화면에 표시하는 설정이었다.

글만 편집할 수 있다면 여기서 시작하기

문제가 생긴 문장의 숫자 범위를 ‘3개월에서 4개월’처럼 풀어 쓴 뒤 미리보기와 공개 화면을 비교한다. 사이트 설정을 직접 관리하지 않아도 시도할 수 있는 방법이다. 같은 문단에 있는 다른 범위 표기도 함께 확인한다.

사이트 설정을 관리한다면 물결표 처리 방식을 확인할 수 있다. 아래에는 실제 증상과 재현 결과, 표기 수정과 설정 변경을 고르는 기준을 정리했다. 이 블로그에서 확인한 4개 글의 의도치 않은 취소선 요소는 합계 9개에서 0개가 됐다. 이는 해당 문서의 표시 결과이며, 모든 Markdown 도구에 같은 설정이 적용된다는 뜻은 아니다.

숫자 범위 표기가 취소선으로 바뀌는 상황을 표현한 개념 일러스트

설명용 일러스트이며 실제 화면 캡처가 아니다.

증상: 숫자 범위 사이의 글자에 취소선이 생긴다

사고는 발행된 공개 페이지의 본문에서 사용자가 의도하지 않은 취소선을 발견해 보고하면서 알려졌다. 장비 납기를 설명하는 문단에서, 본문 중간부터 뒤따라오는 다른 내용까지 한 문단 안의 넓은 구간에 취소선이 그어져 있었다.

원본 Markdown 소스는 이런 형태였다(실제 사고 문단의 구조를 중립 예시로 재구성한 것. 참고: 아래는 사고 재현을 위한 예시 소스이며, 회사 내부 문서 원문이 아니다).

일부 장비 납기가 3~4개월에서 6~8개월로 늘어났다. 이 구간에서
증설 계획을 다시 점검해야 한다.

같은 문단을, GFM(GitHub Flavored Markdown) 취소선 확장이 켜져 있고 단일 물결표까지 취소선으로 파싱하는 렌더러로 변환하면 결과 HTML에 <del> 태그가 나타난다. 이 블로그의 빌드가 쓰는 remark-gfm 플러그인의 기본값이 여기에 해당하며, 아래 출력은 그 기본 설정에서 실제로 재현한 결과다.

<p>일부 장비 납기가 3<del>4개월에서 6</del>8개월로 늘어났다. …</p>

여기서 물결표의 역할을 정확히 볼 필요가 있다. 3~4개월에도, 6~8개월에도 물결표는 각각 하나씩 들어 있다. 범위 표기 하나가 여는 물결표와 닫는 물결표를 따로 갖는 구조가 아니다. 렌더러 입장에서는 문단 안에 서로 짝을 이루지 않은 물결표가 두 개 보이는 것이고, GFM 취소선 규칙이 적용되면 앞쪽 범위의 물결표가 여는 구분자, 뒤쪽 범위의 물결표가 닫는 구분자로 짝지어지면서 그 사이에 있던 “4개월에서 6”이 취소선 콘텐츠로 처리된다. 작성자가 의도한 것은 숫자 범위 두 개였고, 취소선은 단 하나도 없었다.

핵심 특징은 두 가지다.

  1. 한 문단에 물결표가 두 개 이상 있으면 사고가 날 수 있다. 짝이 없으면 취소선이 성립하지 않으므로, 3~4개월 하나만 있는 문단은 물결표가 1개라 짝을 이루지 못하고 리터럴로 남는다(GFM 명세는 취소선을 “짝 이루는(matching pair) 물결표”로 정의한다). 반면 범위를 두 번 이상 쓰면 짝지어질 가능성이 생긴다. 다만 “짝수 개면 무조건 발생”이라고 단정할 수는 없다. 물결표가 어떤 위치에, 어떤 맥락으로 놓이느냐에 따라 짝지어짐 결과가 달라질 수 있기 때문이다. 확실한 것은 위에서 재현한 특정 패턴 — 3~4개월에서 6~8개월로 — 에서 취소선이 실제로 생성된다는 사실이다. 기술 문서에서 “A에서 B로 늘어났다”처럼 범위를 비교하는 문장은 매우 흔하기 때문에, 설정이 어긋난 상태에서는 이 패턴이 여러 글에서 반복되기 쉽다.
  2. 작성 환경에서는 못 볼 수 있다. 편집기·미리보기 도구마다 GFM 취소선 확장을 켜는지, 단일 물결표를 취소선으로 해석하는지가 다르다. 작성 화면에서는 정상으로 보이던 문단이 발행 빌드에서만 취소선이 되는 차이가 생길 수 있고, 이 경우 사고는 공개 페이지에서 뒤늦게 발견된다. (이번 사고도 공개 페이지의 렌더링 결과 보고로 확인됐다.)

한 가지 다행인 경계도 있다. GFM 명세에 따르면 취소선 파싱은 문단 경계를 넘지 않는다 — 새 문단이 시작되면 취소선 해석이 중단된다(GFM Spec §6.5). 그래서 피해는 보통 사고 문단 안쪽으로 한정된다. 반대로 말하면 한 문단이 길수록, 물결표를 많이 담을수록 피해 구간이 넓어진다.

설정별 실제 렌더링 결과

아래 표는 이 블로그의 remark 계열 빌드 파이프라인에서 두 가지 설정으로 실제 변환을 실행해 기록한 결과다(실측값, 2026-09-20 측정. 입력 소스와 출력 HTML을 그대로 옮겼다).

singleTilde 설정입력 Markdown 소스출력 HTML
true(기본값)3~4개월에서 6~8개월로 늘었다.<p>3<del>4개월에서 6</del>8개월로 늘었다.</p>
true(기본값)3\~4개월에서 6\~8개월로 늘었다. (이스케이프)<p>3~4개월에서 6~8개월로 늘었다.</p>
true(기본값)~~의도한 취소선~~<p><del>의도한 취소선</del></p>
false3~4개월에서 6~8개월로 늘었다.<p>3~4개월에서 6~8개월로 늘었다.</p>
false3\~4개월에서 6\~8개월로 늘었다. (이스케이프)<p>3~4개월에서 6~8개월로 늘었다.</p>
false~~의도한 취소선~~<p><del>의도한 취소선</del></p>

표에서 읽을 수 있는 세 가지 사실: ① 기본값(true)에서 숫자 범위 문단이 취소선으로 깨진다. ② 이스케이프(\~)는 두 설정 모두에서 리터럴 물결표로 렌더링된다. ③ false로 바꿔도 이중 물결표 취소선(~~…~~)은 그대로 동작한다 — singleTilde: false는 취소선 기능 전체를 끄는 것이 아니라 단일 물결표 파싱만 끄는 옵션이다.

렌더러가 입력의 물결표를 어떻게 해석하는지 나타내는 설명용 일러스트. 모든 Markdown의 보편 동작을 뜻하지 않는다 (실제 화면 아님)

설명용 일러스트이며 실제 화면 캡처가 아닙니다.

원인: GFM 취소선은 물결표 ‘한 개’로도 동작할 수 있다

취소선은 CommonMark 기본 문법이 아니라 GFM의 확장 기능이다. GFM 공식 명세는 취소선을 “하나 또는 두 개의 물결표(~)의 짝으로 감싼 텍스트”로 정의한다(GFM Spec §6.5 Strikethrough). 명세의 예시 ~~Hi~~ Hello, ~there~ world!는 <del>Hi</del> Hello, <del>there</del> world!로 변환된다. 즉 ~~텍스트~~뿐 아니라 ~텍스트~도 명세상 취소선이 될 수 있다는 뜻이다. 같은 절에는 알아둘 만한 주변 규칙도 있다: 물결표가 세 개 이상이면(~~~not~~~) 취소선이 만들어지지 않고, 새 문단이 시작되면 취소선 파싱이 중단된다.

여기서 중요한 구분이 있다. 이 문제는 “모든 Markdown 렌더러”의 문제가 아니다. 렌더러마다 단일 물결표 처리가 다르다. 예를 들어 이 블로그의 정적 사이트 빌드가 사용하는 remark 계열 파이프라인의 remark-gfm 플러그인은 singleTilde 옵션을 제공한다. 공식 README에 따르면 이 옵션의 기본값은 true이며, 단일 물결표 취소선은 github.com에서는 동작하지만 GFM으로는 “기술적으로 금지되어 있다(technically prohibited)“고 설명한다. 취소선에는 언제나 물결표 2개 이상을 쓸 수 있다는 안내도 같은 절에 있다(remark-gfm README — Options).

즉 기본값 true는 github.com의 실제 동작에 맞춘 쪽이다. 다만 단일 물결표를 대하는 공식 문서의 표현이 완전히 일치하는 것은 아니다 — 명세 §6.5는 예시에서 단일 물결표 취소선을 보여주고, README는 이를 “기술적으로 금지된” 영역으로 설명한다. 문서 간 문언 차이보다 독자에게 중요한 것은 자기가 실제로 쓰는 렌더러가 단일 물결표를 어떻게 처리하는지 확인하는 것이다. 이 글의 나머지 부분은 직접 재현·실측으로 확인한 remark-gfm의 동작과 설정을 다룬다.

정리하면 원인 체인은 이렇다.

  • 한국어 문서 관행: 숫자 범위를 ~로 쓴다 → 한 문단에 ~가 2개 이상 등장
  • 렌더러 설정: GFM 취소선 확장이 켜져 있고 단일 물결표도 취소선으로 파싱한다
  • 결과: 인접한 두 범위의 물결표가 여는/닫는 구분자로 짝지어져 사이 텍스트가 <del>로 감긴다

작성 오류가 아니라 문서 언어 관행과 렌더러 설정의 충돌이다. 그래서 해결도 두 방향 — 표기를 바꾸거나, 설정을 바꾸거나 — 에서 고를 수 있다.

해결: 표기 변경, 이스케이프, 렌더러 설정 세 가지

독자가 자신의 환경에서 쓸 수 있는 선택지는 세 가지다.

선택지안전 범위유지 비용언제 적합한가
① 표기 변경 (3개월에서 4개월, 3-4개월)렌더러 무관, 가장 넓음문서 전체 표기 습관 변경발행 파이프라인을 제어할 수 없을 때
② 물결표 이스케이프 (\~)이스케이프를 지원하는 렌더러에서 리터럴 보장(위 실측 표 참조)글마다 수동 수정·상시 운용 부담기존 표기를 유지하면서 소수 글만 고칠 때
③ 렌더러 설정 (singleTilde: false 등)해당 파이프라인 전체에 일괄 적용설정 1회, 이후 자동빌드 파이프라인을 직접 제어할 때(근본 해결)

1) 범위 표기 자체를 바꾸기. 3~4개월 대신 3개월에서 4개월, 3-4개월(하이픈)로 쓴다. 가장 단순하고 어떤 렌더러에서도 안전하지만, 문서 전체의 표기 습관을 바꿔야 한다.

2) 물결표 이스케이프. Markdown에서 \~처럼 백슬래시로 이스케이프하면 리터럴 물결표로 렌더링된다(위 실측 표에서 두 설정 모두 확인). 표기는 유지할 수 있지만, 글마다 수동으로 찾아 바꿔야 하고 에디터에 따라 이스케이프 처리가 달라질 수 있어 상시 운용 부담이 있다.

3) 렌더러 설정으로 단일 물결표 취소선을 끄기. 발행 파이프라인을 직접 제어할 수 있다면 이 방법이 근본적이다. remark-gfm을 쓰는 환경이라면 공식 README의 예시코드대로 unified 파이프라인에서 플러그인 옵션을 지정한다(아래는 remark-gfm README의 singleTilde 예시를 옮긴 것이며, 파이프라인 앞단의 import·프로세서 구성은 각 환경에 맞게 채워야 하는 구성 예시 코드다).

// … (import remarkParse, remarkRehype, rehypeStringify 등 환경 구성)

const file = await unified()
  .use(remarkParse)
  .use(remarkGfm, {singleTilde: false})
  .use(remarkRehype)
  .use(rehypeStringify)
  .process('~one~ and ~~two~~')

console.log(String(file))

README에 따르면 이 코드의 출력은 <p>~one~ and <del>two</del></p>다. singleTilde: false에서 단일 물결표(~one~)는 리터럴로 남고, 의도적인 이중 물결표 취소선(~~two~~)은 계속 동작한다는 것이 공식 문서로 확인되는 동작이다. 이 구분이 실무에서 중요하다: “취소선이 깨지니 GFM 확장을 통째로 끈다”는 대응은 표·태스크리스트·자동 링크까지 함께 잃는다. singleTilde 옵션은 단일 물결표 파싱만 표적으로 삼으므로, 숫자 범위 표기는 살리고 의도한 취소선 문법은 유지하는 최소 개입 해결책이 된다.

다른 렌더러를 쓴다면 각 렌더러의 공식 문서에서 GFM 취소선 확장 또는 단일 물결표 관련 옵션을 확인해야 한다. 옵션 이름과 기본값은 구현마다 다르다.

QSike 블로그에서는 세 번째 방법을 적용했다. 빌드 설정에서 기본 GFM 처리를 끄고 remark-gfm을 singleTilde: false로 명시적으로 구성해, 숫자 범위 표기는 유지하면서 의도한 이중 물결표 취소선은 계속 쓸 수 있게 했다.

수정 후 확인 절차(출력 비교 → 회귀 테스트 → 발행본 확인)를 나타내는 설명용 일러스트 (실제 화면 아님)

설명용 일러스트이며 실제 화면 캡처가 아닙니다.

확인: 고쳤다는 것은 어떻게 증명하는가

설정을 바꾼 뒤에는 “이제 괜찮을 것”이 아니라 실제 빌드 결과로 확인해야 한다. 이 블로그에서 쓴 확인 절차는 다음 세 단계였고, 같은 방법을 다른 환경에도 적용할 수 있다.

1단계 — 사고 글의 before/after 비교. 수정 배포(2026-09-09) 직전 백업과 현재 빌드(2026-09-20 측정)의 생성 HTML을 비교했다. 지표는 HTML <del> 요소의 개수다. 이 숫자는 검색 순위나 방문자 영향 수치가 아니라, 렌더링 출력에 취소선 태그가 몇 개 남았는지를 세는 구조적 지표라는 점을 분명히 해 둔다.

한 글에서 5개가 한꺼번에 나온 이유는 위에서 설명한 대로다. 장비 납기·증설 일정을 다루는 글은 3~4개월, 6~8개월 같은 범위 표기가 한 문단에 여러 번 등장하기 쉽다.

2단계 — 회귀(regression) 테스트. 의도한 기능이 죽지 않았는지도 확인해야 한다. 다음 세 가지 케이스가 2026-09-20 기준 모두 통과한다.

  1. 숫자 범위 문단: ~가 리터럴로 렌더링되고 <del>이 생성되지 않는가
  2. 의도한 취소선(~~…~~)과 표·태스크리스트·링크·인라인 코드(…)가 기존대로 동작하는가
  3. 실제 발행된 본문 4건 전체를 빌드했을 때 <del>이 0개인가

singleTilde: false는 단일 물결표 파싱만 비활성화하므로 GFM의 나머지 기능(표, 태스크리스트, 자동 링크)에는 영향이 없어야 정상이고, 이번 회귀 케이스에서 확인한 항목들의 결과도 그러했다. 다만 각주는 이번 회귀 테스트로 확인한 항목에 포함되지 않는다.

3단계 — 발행본 육안 확인. 최종 발행 페이지에서 사고 문단이 정상 표기로 보이는지, 취소선으로 남긴 의도적 표현(있다면)이 유지되는지 직접 확인한다.

독자가 자신의 블로그에서 같은 문제를 진단하려면 이렇게 해 볼 수 있다. 브라우저 개발자 도구에서 본문의 취소선이 그어진 부분을 찾아 <del> 태그인지 확인하고, 있다면 그 글을 렌더링하는 도구가 GFM 취소선 확장을 어떤 기본값으로 쓰는지 공식 문서에서 확인한다. 소스 파일에서 한 문단 내 물결표 개수를 세어 물결표가 2개 이상인 문단을 찾는 것도 사고 지점을 빠르게 좁히는 방법이다.

내 환경에서는 무엇부터 바꿀까

내가 바꿀 수 있는 범위먼저 할 일완료 확인
글 내용만 편집 가능숫자 범위를 ‘3개월에서 4개월’처럼 풀어 쓰기같은 문단의 다른 범위까지 공개 화면에서 확인
Markdown 소스 편집 가능물결표 이스케이프를 한 문단에 먼저 적용미리보기와 발행본의 표현이 같은지 비교
렌더러 설정까지 관리사용 중인 플러그인과 버전을 확인한 뒤 단일 물결표 옵션 검토범위 표기는 정상이고 의도한 취소선·표·링크도 유지되는지 확인

검증용 문장은 실제 글과 분리해 보관한다. 숫자 범위가 두 번 들어간 문장, 의도한 취소선, 표와 링크를 각각 준비하면 설정 변경의 영향을 나눠 볼 수 있다. 이 글의 HTML 태그 개수는 해당 글들에서 확인한 결과이며, 다른 문서의 정상 취소선까지 모두 없애야 한다는 뜻은 아니다.

마치며

3~4개월은 지극히 평범한 한국어 기술 문서 표기다. 그것이 취소선이 되는 순간은 작성자의 실수가 아니라, 문서 관행과 렌더러 기본값이 조용히 충돌하는 지점에서 생긴다. GFM 취소선 확장이 단일 물결표까지 허용할 수 있다는 규칙, 그리고 remark-gfm의 singleTilde 같은 구현별 옵션을 알고 있으면, 사고를 미리 예방하거나 발생했을 때 원인을 빠르게 좁힐 수 있다.

바꾼 후에는 반드시 빌드 결과 자체로 확인하자. <del> 개수 세기처럼 단순한 구조 지표 하나와, 의도한 기능이 살아 있는지 보는 회귀 케이스 몇 개면 “고쳐졌다”고 말할 근거가 된다.

확인한 출처 / 근거

  • GFM 공식 명세 §6.5 Strikethrough — 취소선이 “하나 또는 두 개의 물결표”의 짝으로 정의됨, 문단 경계에서 파싱 중단, 물결표 3개 이상은 취소선 아님. GFM 취소선 명세 (2026-09-20 원문 직접 확인)
  • remark-gfm 공식 README — singleTilde 옵션(기본값 true, 단일 물결표는 github.com에서 동작하나 GFM으로는 “기술적으로 금지” 설명)과 singleTilde: false 예시코드·출력(<p>~one~ and <del>two</del></p>). remark-gfm 옵션 및 singleTilde 예시 (2026-09-20 원문 직접 확인)
  • 선행 발행 글(사고 발견 지점, <del> 5개 → 0개): AI 칩 공급 일정, 전공정 증설만으로 앞당길 수 없는 이유 (2026-09-20 공개 접근·현재 제목 확인)
  • 참고: 사고 경위(2026-09-09 운영자 보고·수정 배포, 2026-09-20 근거 재확인)와 before/after <del> 개수(9→0), 회귀 테스트 3건 통과, 설정별 렌더링 실측 표(6행, 공개 패키지 remark-gfm 4.0.1로 동일 출력 재현 확인)는 운영자가 확인한 내부 기록에 근거한 실측값이다. 공개 URL이 없는 내부 빌드 기록이므로 별도 링크를 만들지 않는다. before는 2026-09-09 배포 직전 백업, after는 2026-09-20 현재 빌드 측정으로 시점이 다르며, <del> 개수는 HTML 구조 지표로 검색·트래픽 영향 수치가 아니다.
  • 참고: 본문 중 “일부 장비 납기가 3~4개월에서…” 예시 문단은 실제 사고 패턴을 재현한 중립 예시이며, 특정 내부 문서 원문을 그대로 옮긴 것이 아니다. 회귀 테스트 검증 항목은 인라인 코드까지이며 펜스 코드블록·각주는 검증 단언에 포함되지 않았다.
NEXT READING

같은 주제와 태그를 공유하면서, 이 글의 판단 범위를 다음 단계로 넓혀 주는 해설입니다.

AX·업무 자동화 구글에 글이 안 보일 때: 색인 요청 전에 확인할 것과 기다려야 할 것 색인 요청 접수, 색인, 검색 노출은 서로 다른 사건이다. 실제로 공개된 글 한 개의 URL 검사 기록을 예로 들어, 확인 날짜와 보고 날짜를 구분하고 상태별 판단 기준 표와 복사해서 쓰는 기록 표를 정리한다. AX·업무 자동화 AI에게 블로그 발행을 맡길 때, 어디까지 맡기고 무엇을 직접 확인해야 할까? 다섯 편의 발행 운영 기록에서 뽑은 위임 판단표. 작업별로 AI에게 줄 입력, 기계로 확인할 증거, 사람이 승인할 조건, 멈출 조건을 나눠 정리한다. 완전 자동화 성공담이 아니라 위임 범위를 정하는 기준에 대한 글이다. AX·업무 자동화 글은 있는데 독자가 찾을 수 없다면: 블로그 추천 목록 점검하기 글 주소는 정상인데 추천 목록에서는 빠진 사례다. 사이트를 운영하는 사람이 직접 주소를 여는 검사와 메뉴에서 글을 찾는 검사를 구분하고, 이름이나 주소를 바꾼 뒤 누락을 점검하는 방법을 정리했다.