본문 바로가기
카테고리 없음

블로그 글 목차 자동 생성하는 방법

by richjin7285 2025. 10. 12.

블로그 글 목차 자동 생성하는 방법 사진

긴 글일수록 독자는 먼저 구조를 확인합니다. 스크롤을 내리기 전에 “무엇을, 어떤 순서로” 다루는지 보게 되죠. 이때 가장 강력한 도구가 바로 자동 생성 목차(TOC; Table of Contents)입니다. 수동으로 링크를 일일이 걸 필요 없이, 글의 제목 계층(H2/H3 등)을 읽어 목차를 만들어주고, 클릭하면 해당 섹션으로 부드럽게 이동하며, 현재 위치를 표시(스크롤 스파이) 해 줍니다. 이 글에서는 ① 원리와 설계(헤딩 계층·앵커·접근성), ② 플랫폼별 설정(티스토리/블로그스폿/워드프레스/마크다운),커스텀 구현(JavaScript로 자동 생성/스크롤 스파이/접근성·SEO 최적화)까지, 실전에서 바로 복붙 가능한 코드와 체크리스트로 정리합니다.

1) 원리와 설계: 헤딩 계층·앵커 링크·접근성(스크린리더)·SEO

자동 목차는 결국 “헤딩을 읽어 앵커 링크를 만든다”는 단순한 원리입니다. 그래서 시작은 제목 계층부터 정돈하는 일입니다. 글마다 H1은 1개, 섹션은 H2, 하위는 H3/H4로 깔끔하게 내려가야 목차도 예쁘게 나옵니다. 다음으로 앵커(고유 id)가 있어야 링크가 걸립니다. 플랫폼/테마에 따라 자동으로 id가 붙기도 하지만, 불안정하면 스크립트로 id를 생성해 줍니다. 마지막으로 접근성—목차 컨테이너에 nav·aria-label을 쓰고, 현재 위치는 aria-current="true"로 표시하면 스크린리더에서도 훌륭하게 작동합니다. SEO 면에서도 목차(점프링크)는 검색 결과에 사이트 링크처럼 노출될 가능성을 높여 CTR 향상에 도움을 줍니다.

  • 헤딩 규칙: H1(제목)=1개, 섹션=H2, 하위=H3/H4. 크기 조절은 CSS로, 숫자는 계층 의미입니다.
  • 앵커(id) 규칙: 한 페이지에서 유일(unique)해야 하며, 공백 대신 케밥케이스(예: data-clean-architecture) 사용.
  • 접근성: 목차 래퍼는 <nav aria-label="글 목차">, 현재 항목에는 aria-current="true"로 표시.
  • UX: 클릭 시 부드러운 스크롤(scroll-behavior: smooth;), 현재 위치 하이라이트(스크롤 스파이).
/* 기본 UX: 부드러운 스크롤 */
html { scroll-behavior: smooth; }

/* 목차 기본 스타일 */
.toc { border:1px solid #e5e7eb; border-radius:10px; padding:14px; background:#f8fafc; }
.toc a { color:#334155; text-decoration:none; }
.toc a[aria-current="true"] { color:#2563eb; font-weight:600; }
.toc ol { margin:0; padding-left:18px; }

2) 플랫폼별 자동 목차: 티스토리·블로그스팟·워드프레스·마크다운

플랫폼별 자동 목차 사진

대부분의 블로그 플랫폼은 플러그인/가젯으로 쉽게 목차를 붙일 수 있습니다. 아래는 각 플랫폼에서 흔히 쓰는 경로와, 플러그인을 쓰지 못하는 환경을 위한 간단 삽입 코드입니다.

티스토리(Tistory)

  • 스킨 옵션/플러그인: 최신 스킨은 본문 내 [toc] 단축문 또는 스킨 설정에 목차 표시가 있습니다(스킨 별도 문서 확인).
  • 직접 삽입: 스킨 편집 > skin.html 또는 article.html에 아래 스크립트를 추가하고, 본문 상단에 <div id="toc" class="toc"></div>를 삽입합니다.

Blogger(블로그스폿)

  • 가젯: 기본 가젯은 자동 목차가 없으므로 테마 > HTML 편집에 커스텀 스크립트를 추가하는 편이 일반적입니다.
  • 방법: 포스트 템플릿 상단에 <div id="toc" class="toc"></div>를 넣고, 아래 JS를 테마 하단에 추가.

워드프레스(WordPress)

  • 추천 플러그인: Easy Table of Contents, LuckyWP Table of Contents. 설치 > 활성화 > “포스트 자동 삽입” 체크.
  • 블록: 일부 테마/페이지빌더(Elementor/Divi)에는 TOC 블록이 내장되어 있습니다.
  • 수동: 플러그인 사용이 제한된 환경이면 아래 커스텀 JS를 child theme 또는 Code Snippets로 추가.

마크다운/정적 사이트(Jekyll/Hugo/Hexo)

  • 빌드 플러그인 사용: Jekyll의 jekyll-toc 또는 Hugo의 {{. TableOfContents }} 단축코드.
  • 단일 HTML에서도 아래 스크립트로 쉽게 구현 가능합니다.
플러그인이 안될 때 쓰는 ‘140줄짜리’ 자동 목차 스크립트(복붙)
<div id="toc" class="toc"></div>
<script>
// 간단 TOC 생성기: 본문 내 H2/H3를 읽어 목차 생성 + 스크롤 스파이
(function(){
  const container = document.getElementById('toc');
  if(!container) return;

  const headings = Array.from(document.querySelectorAll('h2, h3'))
    .filter(h => h.textContent.trim().length > 0);

  if(headings.length === 0) { container.style.display='none'; return; }

  // 고유 id 부여(없으면 생성)
  const slugify = s => s.toLowerCase().trim()
    .replace(/[^\w가-힣\s-]/g,'').replace(/\s+/g,'-').replace(/-+/g,'-');
  const ids = new Set();
  headings.forEach(h => {
    if(!h.id) {
      let id = slugify(h.textContent);
      while(ids.has(id)) id = id + '-' + Math.floor(Math.random()*1000);
      h.id = id; ids.add(id);
    }
  });

  // 목록 구조 만들기
  const ol = document.createElement('ol');
  let currentOl = ol, lastLevel = 2;
  headings.forEach(h => {
    const level = +h.tagName.substring(1); // 2 or 3
    if(level > lastLevel){
      const sub = document.createElement('ol');
      currentOl.lastElementChild && currentOl.lastElementChild.appendChild(sub);
      currentOl = sub;
    } else if(level < lastLevel){
      currentOl = currentOl.parentElement.closest('ol') || ol;
    }
    const li = document.createElement('li');
    const a = document.createElement('a');
    a.href = '#' + h.id;
    a.textContent = h.textContent;
    a.setAttribute('data-target', h.id);
    li.appendChild(a);
    currentOl.appendChild(li);
    lastLevel = level;
  });

  const title = document.createElement('div');
  title.style.cssText = 'font-weight:700;margin-bottom:8px;color:#0f172a;';
  title.textContent = '목차';
  container.appendChild(title);
  container.appendChild(ol);

  // 스크롤 스파이
  const links = container.querySelectorAll('a[data-target]');
  const map = {};
  links.forEach(a => map[a.getAttribute('data-target')] = a);

  const observer = new IntersectionObserver(entries => {
    entries.forEach(ent => {
      const id = ent.target.id;
      const link = map[id];
      if(!link) return;
      if(ent.isIntersecting) {
        links.forEach(l => l.removeAttribute('aria-current'));
        link.setAttribute('aria-current','true');
      }
    });
  }, { rootMargin: '0px 0px -70% 0px', threshold: [0, 1] });

  headings.forEach(h => observer.observe(h));
})();
</script>
  

위 스크립트는 본문에 있는 H2/H3를 자동으로 수집해 목차를 만들고, IntersectionObserver로 현재 섹션을 하이라이트 합니다. <div id="toc">만 본문 상단(또는 사이드바)에 배치하면 동작합니다.

3) 커스텀 UX: 고정 목차(Sticky), 스크롤 스파이, 접기/펼치기, 긴 제목 줄임표

목차가 생겼다면, 이제 읽기 경험을 높이는 마무리 디테일을 더해보세요. 긴 글에서 특히 빛납니다.

사이드 고정(Sticky TOC)

/* 2열 레이아웃 예시 */
@media (min-width: 1024px){
  .post-wrap { display:grid; grid-template-columns: 1fr 280px; gap:24px; }
  .toc { position: sticky; top: 92px; max-height: calc(100vh - 120px); overflow:auto; }
}
.toc li { margin:6px 0; }
.toc li li { margin-left:8px; }
.toc a { display:block; padding:2px 0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }

접기/펼치기

<details class="toc">
  <summary style="cursor:pointer;font-weight:700;color:#0f172a;">목차 펼치기/닫기</summary>
  <div id="toc-list"></div>
</details>
<script>
// 위 자동 생성 스크립트에서 container를 document.getElementById('toc-list')로만 바꿔도 동작
</script>

길고 중복되는 제목 줄임표 처리

  • CSS의 text-overflow: ellipsis; 적용(위 코드 포함), 또는 스크립트에서 60자 이상은 자르기.

현재 위치 강조(스크롤 스파이)

  • 앞서 제공한 스크립트에 포함. aria-current="true"를 이용해 굵게/색상 강조.

접근성·키보드 내비게이션

  • nav [aria-label="글 목차"]로 감싸고, 링크는 tabindex 기본 흐름을 따르게 둡니다.
  • 색상 대비(링크 vs 본문) 4.5:1 이상 확보.

SEO 보너스: 점프링크(분절 링크) 유도

  • 핵심 섹션 제목을 질문형/결론형으로 작성하면 검색 결과에 점프링크가 노출될 확률이 조금 올라갑니다. 예) “FAQ: 목차가 안 보일 때?”
  • 긴 글의 경우, 상단에 “이 글은…” 한 줄 요약 + 목차를 배치하면 체류에 긍정적입니다.
문제 해결 체크리스트
  • 목차가 비어 있음 → 본문에 H2/H3가 실제로 존재하는지 확인(굵기만 키운 단순 p 태그는 감지되지 않음).
  • 클릭해도 위치가 안 맞음 → 상단 고정 헤더가 있으면 CSS로 scroll-margin-top: 80px;을 각 헤딩에 적용.
  • 한글 제목 id 충돌 → slugify 로직을 사용하거나 수동 id 지정(<h2 id="설정-방법">).
  • 스킨/테마에서 id를 지움 → 게시 직후 개발자도구로 h2#아이디가 실제 DOM에 남는지 확인.
/* 고정 헤더 보정: 헤딩에 스크롤 여백 */
h2, h3, h4 { scroll-margin-top: 90px; }

결론: ‘자동 목차’는 긴 글의 내비게이션이자 검색 신호다

긴 글의 내비게이션이자 검색 신호 사진

자동 목차는 단순한 편의 기능이 아닙니다. 글의 구조를 한눈에 보여 주고, 독자의 스캔 속도를 높이며, 검색 결과에서 점프링크 노출까지 노릴 수 있는 강력한 구성 요소입니다. 핵심은 세 가지입니다. 첫째, 헤딩 계층을 올바르게—H1은 1개, 섹션은 H2, 하위는 H3/H4. 둘째, 플랫폼에 맞춰 플러그인/가젯 또는 짧은 커스텀 스크립트로 자동 생성을 붙일 것. 셋째, UX 디테일—부드러운 스크롤, 현재 위치 하이라이트(스크롤 스파이), 스티키 사이드, 접근성 라벨링을 챙길 것. 오늘 글 상단에 <div id="toc">를 하나 두고, 위 스크립트를 붙여 보세요. 목차가 생기는 순간, 글의 체감 퀄리티와 독자의 체류는 즉시 달라질 것입니다.