블로그 꽃단장 파일 공유(w/claude)
skin-share.html 코드 가이드
— 파일 구조, 동작 원리, 커스터마이징 지점
tistory-skin-guide.md(제작 과정/이슈 해결기)와 함께 보는 코드 레퍼런스입니다.
이 문서는 "코드가 어떻게 생겼고, 어디를 고치면 무엇이 바뀌는가"에 집중합니다.
1. 파일 한 장 요약
skin-share.html 하나에 HTML + CSS + JS가 전부 들어있습니다. (약 1,300줄)
skin-share.html
├─ <head>
│ ├─ Google Fonts 로드 (Nanum Pen Script / Noto Serif KR / Noto Sans KR)
│ └─ <style> ······································ 약 10~590행
│ ├─ ① 디자인 토큰 (:root / body.dk)
│ ├─ ② 베이스 & 레이아웃 (헤더, 그리드, 사이드바)
│ ├─ ③ 글 카드 + 미리보기 클램프
│ ├─ ④ 페이지네이션
│ ├─ ⑤ 사이드바 위젯 (검색/카테고리/태그/RSS)
│ ├─ ⑥ Tistory 자동 삽입 요소 덮어쓰기 (!important 지대)
│ ├─ ⑦ 첨부파일 재스타일 + 확장자 칩
│ └─ ⑧ 상세 페이지 모드 (body.detail …)
├─ <body class="tt-body-page">
│ ├─ 헤더 (블로그명, 카테고리 내비, 다크모드 토글)
│ ├─ 메인 컬럼: <s_list> 글 목록 + <s_article_rep> 글 상세
│ │ └─ 카드 내부에 태그/명함/댓글 등 "상세 전용 요소" 동봉
│ ├─ 사이드바: 검색 / 카테고리 / 태그 클라우드 / RSS
│ └─ 푸터
└─ <script> ········································ 약 724~1330행
├─ (a) localStorage 캐시 정리
├─ (b) 첨부파일 DOM 재구성
├─ (c) 페이지네이션 재구성
├─ (d) 페이지 타입 감지 + 상세 모드 토글 ← 가장 큰 블록
│ ├─ 사이드바 카테고리 재구성
│ ├─ 글 태그 정리(멀티 태그 분리) + 폴백
│ ├─ author-box / atags 중복 제거
│ └─ 사이드바 태그 클라우드 정리
├─ (e) 다크모드 토글 + 복원
└─ (f) 스크롤 진행 바
2. 디자인 토큰 — 색/스타일을 바꾸려면 여기만
모든 색상은 CSS 변수로 선언되어 있고, 라이트/다크가 같은 변수명을 공유합니다.
변수만 바꾸면 전체 테마가 일괄 변경됩니다.
:root { /* 라이트 모드 */
--ac:#B07828; /* 액센트 (브론즈) — 링크 호버, 현재 페이지, 칩 */
--ac-a:rgba(176,120,40,.13); /* 액센트 연한 배경 */
--bg:#F8F6F3; --nav:#EFE9E2; /* 페이지 배경 / 내비 배경 */
--tx:#1A1814; --sub:#4A4238; --mt:#6E665E; /* 본문 / 보조 / 메타 텍스트 */
--bd:#E4DDD5; --tb:#EDE7DF; --cb:#FFFEFB; /* 보더 / 태그 배경 / 카드 배경 */
}
body.dk { /* 다크 모드 — 같은 변수를 어두운 값으로 재정의 */ }
| 바꾸고 싶은 것 | 수정 위치 |
|---|---|
| 포인트 컬러 | --ac, --ac-a (라이트/다크 각각) |
| 전체 배경 톤 | --bg, --cb, --bd |
| 본문 폰트 | body{font-family:...} + <head>의 Google Fonts 링크 |
| 로고 손글씨체 | Nanum Pen Script 사용처 (헤더 로고, 아바타 이니셜) |
규칙: 색을 하드코딩하지 말 것. 새 요소를 추가할 때도 var(--ac) 등 변수를 쓰면
다크모드가 공짜로 따라옵니다. (예외: 확장자 칩 색상은 파일 형식 고유색이라 하드코딩)
3. 한 장 두 모드: 목록 ↔ 상세
이 스킨의 핵심 트릭입니다. 카드(.card) 마크업은 하나인데,
body 클래스에 따라 두 가지 모습으로 렌더됩니다.
목록 모드 (기본) 상세 모드 (body.detail)
┌─ .card ──────────┐ .card → 보더/배경 제거, 아티클화
│ 제목 (.pt) │ .pt → 28px 대제목
│ 미리보기 2줄 (.pe) │ .pe → 클램프 해제, 전문 표시
│ 태그 (compact) │ .rep-extra → 표시 (명함, 댓글 등)
└──────────────────┘ + "← 목록으로" 링크 JS 삽입
동작 순서:
<body class="tt-body-page">→ Tistory가tt-body-page(상세) 등으로 치환- JS(d블록)가 클래스를 읽어
body.detail클래스를 추가/생략 - CSS의
body.detail ...섹션(⑧)이 카드를 아티클로 변환
// 정식 판별 우선, 변수 미처리 시 휴리스틱 폴백
if (/tt-body-/.test(bodyCls)) {
isDetail = /tt-body-page(\s|$)/.test(bodyCls);
} else {
isDetail = cards.length === 1;
}
상세 전용 요소 패턴: 명함·댓글처럼 상세에서만 보일 요소는 카드 안에class="rep-extra"로 넣어두고 기본 display:none, body.detail에서만 표시합니다.
새 상세 전용 요소를 추가할 때 이 클래스만 붙이면 됩니다.
4. 미리보기 클램프 — .pe의 방어 설계
목록의 본문 미리보기는 Tistory가 어떤 HTML이든 넣을 수 있는 영역입니다.
그래서 3중 방어를 합니다:
.pe{ max-height:53px !important; overflow:hidden !important;
display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; }
.pe img,.pe figure,.pe video,.pe iframe,.pe table{ display:none !important; } /* 미디어 제거 */
.pe *{ font-size:14px !important; margin:0 !important; ... } /* 평탄화 */
상세 모드에서는 이걸 전부 해제합니다 (body.detail .pe{max-height:none !important;...}).
미리보기 줄 수를 바꾸려면 -webkit-line-clamp 값과 max-height(줄수 × line-height)를 함께 수정하세요.
5. !important 지대 — Tistory 덮어쓰기 레이어
⑥~⑦ 섹션은 거의 모든 선언에 !important가 붙어 있습니다. 버그가 아니라 의도입니다.
Tistory가 런타임에 자체 CSS와 인라인 스타일을 주입하기 때문에, 이를 이기려면 필요합니다.
주요 덮어쓰기 대상:
| 대상 | 처리 |
|---|---|
| 공감/구독/프로필 위젯 | display:none (스킨 자체 디자인으로 대체) |
another_category (카테고리의 다른 글) |
테이블 → 이전 글/다음 글 2칸 카드 그리드로 변환. tr:first-child::before{content:'← 이전 글'} 같은 가상요소로 라벨링 |
| 첨부파일 블록 | 기본 아이콘 숨기고 확장자 칩 + DOWNLOAD 텍스트 링크로 재구성 |
| 본문 표 | border-collapse + 변수 기반 보더로 통일 |
| 댓글 React 앱 | [class*="tt_"] 셀렉터로 폰트/색만 덮어씀 (DOM은 건드리지 않음) |
여기를 수정할 때 주의: 셀렉터가 div[class*="another_category"]처럼 부분 일치인 이유는
Tistory가 클래스명을 바꾸는 경우가 있어서입니다. 정확한 클래스명에 의존하지 마세요.
6. JS 모듈별 가이드
전부 IIFE(즉시실행함수)로 독립되어 있어 하나가 죽어도 나머지는 동작합니다.
중요 로직은 try/catch로 감싸고, 실패 시 console.warn('[hyos] ...')을 남깁니다.
(b) 첨부파일 재구성
.tt_attachment등에서 파일명/크기/링크를 파싱- 확장자를 추출해
<span class="file-ext-ico" data-ext="pdf">칩 삽입 - 새 확장자 색을 추가하려면: CSS의
.file-ext-ico[data-ext="..."]규칙 한 줄 추가
(c) 페이지네이션 재구성
- 서버가 렌더한 번호 링크에서
현재 페이지(href 없는 항목),전체 페이지,URL 패턴을 수집 ‹ 1 … 4 5 6 … 23 ›형태로 다시 그림- 윈도우 크기 변경:
var win = 2(현재 ±2) 값 수정 - 변수 미치환(
[##_잔존) 시 페이지네이션 전체 숨김 — raw 텍스트 노출 방지
(d) 페이지 타입 감지 블록 (메인)
가장 큰 블록. 내부 순서가 중요합니다:
1. body_id로 상세/목록 판별 → body.detail 토글
2. 상세면: "← 목록으로" 링크 삽입
3. 사이드바 카테고리 재구성 ← try/catch (실패해도 원본 노출)
4. 글 태그 정리: '#' 멀티 태그 분리 → 칩 재구성
└ 폴백 사다리: s_tag_label 결과 → 본문 /tag/ 링크 → 페이지 JSON
→ 모바일 페이지(/m/...) fetch → 전부 실패 시 숨김
5. author-box / atags 중복 제거
6. 사이드바 태그 클라우드 정리 (멀티 태그 분리 동일 적용)
태그 폴백은 0ms / 800ms / 2500ms 3회 재시도합니다 — Tistory React가
비동기로 마운트되기 때문. 이 패턴은 React 영역을 읽는 모든 코드에 필요합니다.
(e) 다크모드
document.getElementById('b').classList.toggle('dk', dk); // className= 금지!
localStorage.setItem('hyos-dark', dk ? '1' : '0');
classList.toggle을 쓰는 이유:className =으로 덮어쓰면 Tistory의tt-body-page클래스가 날아가 레이아웃이 깨집니다 (실제 겪은 버그)- 새로고침 시 localStorage에서 복원
(f) 스크롤 진행 바
헤더 위 2px 바(#prog)의 너비를 스크롤 비율로 갱신. 필요 없으면#prog 요소와 마지막 scroll 리스너만 지우면 됩니다.
7. 공통 패턴 (새 기능 추가 시 따라할 것)
패턴 1 — 미치환 변수 가드
if (/\[##_/.test(el.innerHTML)) { /* 변수 미처리 → 폴백 or 숨김 */ }
모든 동적 영역의 첫 줄. raw 텍스트가 사용자에게 노출되는 것을 막습니다.
패턴 2 — 폴백 사다리
정식 치환자 → DOM 정규화 → 대체 소스(RSS, /m/ 페이지) → 깔끔하게 숨김
어느 단계에서 성공하든 결과 UI는 동일하게. 전부 실패하면 빈 껍데기 대신 섹션 자체를 숨깁니다.
패턴 3 — 비동기 재시도
if (!run()) {
setTimeout(function(){ run(); }, 800);
setTimeout(function(){ run(); }, 2500);
}
Tistory React 마운트를 기다리는 표준 방법. MutationObserver보다 단순하고 충분합니다.
패턴 4 — 네임스페이스
- CSS 클래스:
hyos-file,hyos-cmt처럼 접두사 사용 (Tistory 클래스와 충돌 방지) - 콘솔 로그:
console.log('[hyos] ...')— 필터링 가능 - localStorage 키:
hyos-dark,hyosTagCache_v1— 버전 붙여서 마이그레이션 대비
8. 커스터마이징 빠른 레시피
| 하고 싶은 것 | 방법 |
|---|---|
| 포인트 컬러 변경 | :root와 body.dk의 --ac, --ac-a 수정 |
| 미리보기 3줄로 | .pe의 -webkit-line-clamp:3 + max-height 재계산 |
| 사이드바 위젯 순서 변경 | <aside class="sb"> 안의 .ss 블록 순서 바꾸기 |
| 사이드바 위젯 제거 | 해당 .ss 블록 삭제 (JS는 요소 없으면 자동 skip) |
| 페이지네이션 윈도우 | JS의 var win = 2 수정 |
| 확장자 칩 색 추가 | .file-ext-ico[data-ext="확장자"]{background:...} 추가 |
| 다크모드 기본값 ON | (e) 복원 IIFE에서 localStorage 체크 앞에 dk=true;... 분기 추가 |
| 명함(author-box) 수정 | class="author-box" 블록 — 이름/소개/이니셜은 플레이스홀더 검색 |
| 댓글 영역 스타일 | #hyos-cmt 하위 CSS — DOM 구조는 Tistory React 소유, CSS만 건드릴 것 |
9. 수정 시 지켜야 할 것 (안 깨뜨리는 법)
<s_...>블록 구조를 옮기지 마세요. 치환자는 자기 블록 안에서만 동작합니다.
특히<s_tag_label>,<s_random_tags>(반복 단위 주의),<s_paging_rep>.는href="..."로 감싸면 안 됩니다. 속성 전체를 출력하는 변수입니다.- body 클래스는
classList로만 조작하세요. - React 마운트 포인트(
data-tistory-react-app) 내부 DOM을 JS로 수정하지 마세요.
리렌더 시 덮어써집니다. CSS 덮어쓰기만 허용. - JS 추가는 새 IIFE로. 기존 블록에 끼워 넣지 말고 독립 블록 + try/catch로 추가하면
실패해도 다른 기능이 살아 있습니다. - 수정 후에는 5종 페이지를 모두 확인: 홈 / 글 상세 / 카테고리 / 태그 검색 / 마지막 페이지(글 1개).
깃허브로 따로 관리를 하고있지 않아서 파일로 전달 드리니 참고바랍니다~
'IT' 카테고리의 다른 글
| 티스토리 블로그 꽃단장 가이드 및 이슈 노트(w/ Claude Design) (0) | 2026.06.12 |
|---|---|
| [Claude] Claude 엄청남, 엄청남, 엄청남, 평서문 (2) | 2026.04.30 |