티스토리 스킨을 직접 만들며 깨진 것들 — 증상만 봐서는 원인을 못 찾는 5가지
티스토리 스킨(블로그 화면 전체를 만드는 템플릿 파일)을 설치형 대신 직접 만들어 올렸습니다. HTML과 CSS를 쓸 줄 알면 금방 되겠다고 생각했는데 정작 시간을 잡아먹은 건 디자인이 아니라 증상만 봐서는 원인을 짐작할 수 없는 버그들이었습니다.

공통점이 하나 있습니다. 제 컴퓨터에서 미리보기로 열면 전부 멀쩡했습니다. 실제 블로그에 올려야만 다시 나타났고 그래서 “올리기 전에 다 확인했는데 왜"라는 상황이 반복됐습니다.
기억나는 것 다섯 개를 원인까지 적어둡니다.
1. 홈은 멀쩡한데 글 페이지만 무한 로딩

가장 오래 헤맨 것입니다. 홈은 정상적으로 뜨는데 글을 클릭하면 스피너(빙글빙글 도는 로딩 표시)가 계속 돕니다. CSS를 의심하고 이미지 경로를 의심하고 스크립트를 지워보기도 했지만 전부 아니었습니다.
정정 (2026-09-20) — 아래 진단은 틀렸습니다. 로딩을 푼 것은
댓글 치환자(서버가 내용을 채워 넣도록 스킨에 미리 두는 자리 표시)가 아니라
발행된 글이 하나 생긴 것이었습니다. 같은 때 넣은 치환자는 그 뒤 4주 동안 아무것도
그리지 않았습니다. 치환자만 두면 서버가 그 자리를 그대로 지웁니다.
<s_rp> 로 감싸야 합니다. 재현과 근거는
댓글창이 4주 동안 비어 있었습니다에 적었습니다.
당시 기록이라 본문은 그대로 두고 코드만 맞는 형태로 바꿔 둡니다.
아래 진단은 당시 제가 내린 것이고, 위 정정 상자대로 틀렸습니다
원인은 댓글이었습니다.
티스토리가 끼워 넣는 common.js는 글 페이지에서 React 댓글 위젯을 붙이려고 합니다.
그런데 붙일 자리([##_comment_group_##])가 스킨에 없으면 붙이지 못한 채로 멈춥니다.
댓글을 붙이려다 페이지 전체가 멈춥니다.
<!-- 2026-09-20 정정: <s_rp> 로 감싸야 한다.
치환자만 두면 서버가 빈 문자열로 지워서 댓글창이 아예 안 생긴다 -->
<div class="area-reply">
<s_rp>
[##_comment_group_##]
</s_rp>
</div>
진단 요령: 홈은 정상인데 글 페이지만 멈추면 발행된 글이 0개인 경우를 먼저 봅니다. 스킨을 만들자마자 테스트하면 여기 걸리는데 스킨 문제로 착각하기 쉽습니다. 글을 하나 발행하고 다시 여는 것이 가장 빠른 판별입니다. 증상이 “로딩"이라 네트워크나 이미지를 먼저 의심하게 되는데 콘솔(브라우저 개발자 도구에서 오류 메시지가 찍히는 창)을 보면 답이 빨리 나옵니다.
댓글창은 로딩과 별개로 확인해야 합니다. 스피너가 멈춘 것과 위젯이 뜬 것은 다른 사건입니다.
2. $ is not a function

콘솔에 $ is not a function과 Cannot read 'initTracker'가 같이 떴습니다.
jQuery가 없다는 뜻인데 티스토리가 알아서 끼워 넣어 준다고 알고 있었습니다.
s_t3 태그의 위치가 잘못돼 있었습니다.
그냥 표시용 태그처럼 보여도 이건 티스토리가 자기 기본 스크립트(common.js)를 끼워 넣는 영역 표시입니다.
저는 이걸 빈 태그로 <head>에 하나 넣어뒀는데 그러면 끼워 넣을 영역이 없습니다.
<body> 바로 뒤부터 </body> 앞까지 본문 전체를 감싸는 형태가 맞습니다.
공식 문서와 참고용 테마 모두 그렇게 되어 있었습니다.
근거 — 티스토리 공식 스킨 문서는 이 태그를 「티스토리 공통 javascript 삽입 (필수)」로 설명하고,
<body> 안을 통째로 감싼 예시와 치환된 뒤 common.js 가 들어간 결과를 나란히 싣고 있습니다
(공통 치환자 문서).
티스토리가 공개한 참고 테마 ray 도 같은 배치로, 여는 태그가 <body> 바로 다음 줄에 있고 닫는 태그가 </body> 앞에 있습니다
(skin.html).
처음에는 이 영역이 jQuery 도 넣어 준다고 적었는데 2026-09-22 에 다시 재보니 아니었습니다 —
공식 문서의 치환 후 예시에 들어가는 것은 common.js 하나뿐이고, 제 글 페이지 소스에서
jquery-3.5.1.min.js 는 <body> 보다 앞선 <head> 안에 실린 뒤 바로 jQuery.noConflict(true) 로
전역에서 걷힙니다. ray 도 jQuery 를 자기 <head>에서 직접 불러옵니다. 문서·테마는 2026-09-21,
소스 재측정은 2026-09-22 확인입니다.
그러니 스킨 자체 스크립트는 그 영역이 끝난 뒤에 두는 편이 안전합니다.
참고 테마 ray 도 </s_t3> 뒤에서 자체 스크립트를 불러 거기서 jQuery 를 씁니다.
안쪽에 뒀을 때 어떻게 되는지는 확인해 보지 않았습니다.
3. 메뉴를 누르면 “권한이 없습니다”

제가 만든 스킨의 메뉴와 필터 버튼에 /tag/제철, /category/베이킹 같은 주소를
직접 적어뒀습니다. 눌러보니 “권한이 없습니다"가 떴습니다.
권한에는 문제가 없었고 그런 태그와 카테고리가 존재하지 않았을 뿐입니다. 없는 분류를 열었는데 404(그런 주소가 없다는 응답)가 아니라 권한 오류가 돌아오니 원인이 안 보였습니다.
이 응답은 당시 관측입니다. 2026-09-21에 없는 카테고리와 태그를 한글 이름과 숫자 ID로 네 가지 형태로 다시 요청해 봤더니 전부 404 였고 「권한이 없습니다」 문자열은 나오지 않았습니다. 지금은 재현되지 않고, 어떤 조건에서 권한 오류가 나왔는지는 확인하지 못했습니다. 없는 주소를 적어두면 링크가 깨진다는 사실 자체는 그대로지만, 화면에 무엇이 뜨는지는 지금 직접 눌러 보고 확인하시는 편이 낫습니다.
주소를 직접 적어두는 방식을 버리니 해결됐습니다.
<!-- 존재하는 항목만 자동으로 렌더된다 → 죽은 링크가 원천적으로 안 생긴다 -->
<nav>[##_blog_menu_##]</nav>
<div class="pills">[##_category_list_##]</div>
이 방식의 값어치는 분류를 바꿀 때 드러납니다. 분류를 직접 적으면 그 분류를 지웠을 때 링크가 죽지만 자동 치환자는 실제로 있는 것만 뱉으므로 그런 일이 생기지 않습니다. 수동으로 맞추고 싶은 유혹이 들 때마다 이걸 떠올렸습니다.
2026-09-21에 제 블로그 첫 화면에서 치환자가 그린 분류 링크를 전부 뽑아 응답 코드를 찍어 봤습니다. 6개 전부 200이었고 죽은 링크는 없었습니다.
4. 카드가 그리드를 무시하고 1열로 쌓임

홈에 글 카드를 격자로 깔았는데 한 줄에 하나씩 세로로만 쌓였습니다. CSS를 아무리 고쳐도 안 됐습니다.
CSS가 아니라 DOM 구조, 즉 브라우저가 화면을 그리려고 만든 태그의 짜임새가 원인이었습니다. 티스토리 치환자가 카드를 뱉을 때 겉을 태그로 한 번 감싸서 나옵니다. 격자를 만들 바깥 상자 입장에서는 안에 든 것이 하나뿐이었으니 격자가 될 수가 없습니다.
/* 래퍼를 레이아웃에서 투명하게 만들어 자식이 그리드 항목이 되게 한다 */
.wrapper { display: contents; }
display: contents는 그 태그가 차지하던 자리를 없애서 안에 든 것들이 바로 윗 단계의 항목처럼 취급되게 합니다.
치환자가 씌우는 이 겉 태그는 걷어낼 수 없었습니다. 그럴 때 쓸 수 있는 거의 유일한 방법이었습니다.
위 .wrapper 는 설명하려고 붙인 이름입니다. 그대로 붙여넣으면 걸리는 게 없으니,
실제로는 올린 뒤 소스를 열어 치환자가 뱉은 겉 태그의 이름을 확인하고 그 선택자에 걸어야 합니다.
제 스킨에는 검색 영역·푸터 분류 목록·분류 타일·글 반복 영역 네 군데에 같은 규칙이 들어가 있습니다.
5. 주석에 적은 태그 이름이 실제로 동작해버림

이게 가장 이상했던 것입니다. 예방 차원에서 알아둔 것이라 실제로 터지진 않았지만 터졌다면 원인을 절대 못 찾았을 것 같습니다.
티스토리의 치환 엔진이 HTML 구조를 이해하고 읽는 것이 아니라 글자를 찾아 그대로 바꿔치기하는 방식이라면, HTML 주석 안에 적은 태그 이름도 진짜 태그로 보게 됩니다.
<!-- 이 영역은 s_t3 종료 태그 뒤에 와야 한다 -->
주석에 설명하려고 종료 태그를 그대로 적으면 엔진이 거기서 영역을 끊을 수 있고, 그러면 그 아래 전체가 티스토리 스크립트 없이 그려집니다 — 2번과 똑같은 증상인데, 소스를 봐도 주석일 뿐이라 눈에 안 들어옵니다.
여기는 확인하지 못한 항목입니다. 주석 안에 종료 태그 문자열을 실제로 적어둔 것을 올리기 전 점검에서 발견해 지웠고, 그대로 올렸을 때 정말 영역이 끊기는지는 재현해 보지 않았습니다. 「이렇게 되더라」가 아니라 「이럴 것 같아 피했다」로 읽어 주시면 됩니다.
주석에는 태그 문자열을 쓰지 않고 말로 풀어 적기로 했습니다.
같은 함정을 한 번 더 밟았습니다. 스킨을 정리하면서 왜 지웠는지를 HTML 주석으로 꼼꼼히 남겼는데 올리고 나서 보니 그 주석이 실제 블로그 소스에 그대로 나와 있었습니다. 세어 보니 7덩이 4,189바이트였습니다. 당연한 일인데 작업할 때는 생각이 안 났습니다. 그 뒤로 왜 지웠는지 같은 경위는 스킨이 아니라 따로 쓰는 작업 메모에 적습니다.
스킨에는 「이 자리를 지우면 글 페이지가 멈춘다」처럼 다음에 만질 때 필요한 한 줄만 남깁니다. 다만 그 한 줄도 소스에 그대로 나갑니다 — 2026-09-21 기준 제 스킨에 13개가 남아 있고 첫 화면 소스에서도 그대로 읽힙니다. 남길 거라면 남이 읽어도 되는 내용만 남겨야 합니다.
정리 — 다섯 개의 공통점

| 증상 | 실제 원인 | 짐작 가능했나 |
|---|---|---|
| 글 페이지만 무한 로딩 | 발행된 글이 0개 (1번 정정 상자 참고 — 당시엔 댓글 자리 부재로 봤습니다) | ❌ |
$ is not a function | 영역 태그를 head에 둠 | ❌ |
| “권한이 없습니다” | 없는 분류를 직접 적어 둠 (2026-09-21 재요청에서는 404) | ❌ |
| 카드가 1열로 쌓임 | 치환자가 겉 태그를 씌움 | ❌ |
| 영역이 중간에 끊김 | 주석 안의 태그 문자열 (겪지 않음 · 재현 안 해 봄) | ❌ |
전부 증상에서 원인으로 가는 길이 직관적이지 않습니다. 그리고 실제로 겪은 것들은 모두 제 컴퓨터 미리보기에서는 재현되지 않았습니다. 티스토리가 실제로 끼워 넣는 것들이 실제 블로그에만 있기 때문입니다.
그래서 결국 이렇게 정리했습니다.
- 추측으로 고치지 않는다. 공식 문서와 참고용 테마를 먼저 대조합니다. 대부분이 “그렇게 쓰는 게 아니었다"였습니다.
- 실제 블로그에 올린 뒤 콘솔을 본다. 내 컴퓨터에서 멀쩡한 것이 증명이 되지 않습니다.
- 막히면 콘솔 캡처가 가장 빠른 단서다. 증상 설명보다 오류 문자열 하나가 낫습니다.
디자인을 고민한 시간보다 이 다섯 개에 쓴 시간이 길었습니다. 스킨을 직접 만들 생각이라면, HTML/CSS 실력보다 이 플랫폼이 무엇을 끼워 넣는지를 미리 알아두면 좋겠습니다.