자동목차구현하기-마크업 언어 h2 태그 아래 목차 넣는 방법(+ JavaScript 코드, css코드 구현하기)
계층형 목차 로직을 유지하면서, 요청하신 대로 1. 첫 번째 <h2> 태그 위에 목차를 배치하고 2. 이미지와 유사한 닫힘/펼침 디자인(화살표 토글)을 적용하도록 코드를 수정했습니다.
목차 컨테이너의 모양을 이미지처럼 구현하기 위해 필요한 최소한의 CSS 코드도 함께 제공합니다.
📋 수정된 JavaScript 코드 (첫 h2태그 위 배치 및 화살표 토글)
JavaScript
<script>
//<![CDATA[
// JavaScript를 이용한 자동 목차 생성 로직
function generateTOC() {
// 1. 블로그 게시물 본문 요소를 찾습니다.
const postBody = document.querySelector('.post-body') || document.querySelector('.entry-content') || document.querySelector('.post-content');
// 게시물 본문을 찾지 못하거나 목차 생성 제외 태그가 발견되면 종료
if (!postBody) return;
if (postBody.querySelector('.no-toc')) return;
// 2. H2, H3, H4 태그를 모두 찾습니다. (H1은 게시물 제목이므로 제외)
const headings = postBody.querySelectorAll('h2, h3, h4');
if (headings.length < 2) return; // 최소 두 개 이상의 제목이 있어야 목차를 생성합니다.
// 3. 목차(TOC) 컨테이너 및 토글 영역 생성 (이미지 모양 반영)
const tocContainer = document.createElement('div');
tocContainer.id = 'auto-toc-container';
tocContainer.className = 'toc-box-style'; // CSS 적용을 위한 클래스
// 3-1. 토글 헤더 영역 (Contents + Arrow) 생성
const tocToggle = document.createElement('div');
tocToggle.className = 'toc-toggle-header';
// 이미지처럼 'Contents'와 '>' 모양으로 시작
tocToggle.innerHTML = '<span class="toc-icon-list">☰</span> Contents <span class="toc-arrow">►</span>';
tocContainer.appendChild(tocToggle);
// 3-2. 목차 리스트 내용을 담는 컨테이너 생성
const tocContent = document.createElement('div');
tocContent.className = 'toc-content-collapsible';
tocContent.style.display = 'none'; // 초기 닫힘 상태
tocContainer.appendChild(tocContent);
// 최상위 리스트 (H2 레벨) 시작
let tocList = document.createElement('ol');
tocList.className = 'toc-list-level-1';
tocContent.appendChild(tocList);
let currentList = tocList;
let currentLevel = 2;
headings.forEach((heading, index) => {
const level = parseInt(heading.tagName.substring(1));
// 4. 고유 ID 생성 및 할당 (앵커 링크 연결을 위해 필수)
const headingId = 'toc-heading-' + (index + 1) + '-' + heading.textContent.replace(/[^a-z0-9]/gi, '').substring(0, 10).toLowerCase();
heading.id = headingId;
// 5. 계층 구조에 맞게 리스트 조정 (들여쓰기 로직 유지)
while (currentLevel < level) {
const newList = document.createElement('ol');
newList.className = `toc-list-level-${level}`;
if (currentList.lastChild) {
currentList.lastChild.appendChild(newList);
} else {
currentList.appendChild(document.createElement('li')).appendChild(newList);
}
currentList = newList;
currentLevel++;
}
while (currentLevel > level) {
currentList = currentList.parentNode.closest('ol');
if (!currentList) {
currentList = tocList;
break;
}
currentLevel--;
}
// 6. 목차 항목 (li) 생성 및 현재 리스트에 추가
const listItem = document.createElement('li');
const link = document.createElement('a');
link.href = '#' + headingId;
link.textContent = heading.textContent;
listItem.appendChild(link);
currentList.appendChild(listItem);
currentLevel = level;
});
// 8. 💡 수정된 부분: 토글 기능 추가 및 화살표 변경
tocToggle.addEventListener('click', function() {
const arrow = tocToggle.querySelector('.toc-arrow');
if (tocContent.style.display === 'none') {
tocContent.style.display = 'block';
arrow.innerHTML = '▼'; // 펼칠 때: ▼ (아래 화살표)
} else {
tocContent.style.display = 'none';
arrow.innerHTML = '►'; // 닫을 때: ▶ (오른쪽 화살표)
}
});
// 7. 💡 수정된 부분: 목차를 첫 번째 <h2> 태그 위에 삽입
const firstH2 = postBody.querySelector('h2');
if (firstH2) {
postBody.insertBefore(tocContainer, firstH2);
} else {
// H2가 없으면 (대안으로) 본문 맨 앞에 삽입
postBody.insertBefore(tocContainer, postBody.firstChild);
}
}
// 페이지 로드 후 generateTOC 함수를 실행합니다.
window.onload = function() {
setTimeout(generateTOC, 500);
};
//]]>
</script>
🎨 디자인 구현을 위한 CSS 코드 (필수)
이미지와 같은 디자인을 구현하려면 아래 CSS 코드를 테마의 사용자 정의 CSS 영역 (워드프레스의 경우 외모 > 사용자 정의하기 > 추가 CSS) 또는 <head> 태그 내 <style> 태그 안에 삽입해야 합니다.
CSS
/* 1. 전체 목차 컨테이너 스타일 */
#auto-toc-container.toc-box-style {
border: 1px solid #ddd;
/* margin: 20px 0; */ /* H2 위에 배치되므로 margin 조정이 필요할 수 있습니다. */
margin-bottom: 25px; /* 본문과 간격 */
background-color: #f7f7f7;
border-radius: 4px;
font-size: 16px;
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
}
/* 2. 토글 헤더 (Contents) 스타일 - 이미지의 회색 박스 */
.toc-toggle-header {
background-color: #fcfcfc;
border-bottom: 1px solid #ddd;
padding: 12px 15px;
cursor: pointer;
font-weight: bold;
color: #333;
display: flex; /* 아이콘과 화살표를 정렬 */
justify-content: space-between; /* 양 끝에 배치 */
align-items: center;
border-radius: 4px 4px 0 0;
}
/* 3. 리스트 아이콘 (☰) 스타일 */
.toc-icon-list {
margin-right: 10px;
font-size: 1.1em;
line-height: 1;
}
/* 4. 화살표 스타일 (오른쪽 정렬) */
.toc-arrow {
font-size: 1.1em;
font-weight: normal;
color: #555;
}
/* 5. 목차 내용 (리스트) 스타일 */
.toc-content-collapsible {
padding: 15px;
}
/* 6. 리스트 항목 스타일 */
.toc-content-collapsible ol {
padding-left: 20px;
margin-top: 5px;
margin-bottom: 5px;
}
/* 7. 계층별 리스트 스타일 */
.toc-list-level-1 {
/* 최상위 리스트 (H2) */
list-style-type: decimal; /* 1, 2, 3... */
}
.toc-list-level-2, .toc-list-level-3 {
/* 하위 리스트 (H3, H4) */
list-style-type: disc; /* •, o, ■ 등 */
margin-left: 15px;
}
.toc-content-collapsible a {
text-decoration: none;
color: #0073aa; /* 링크 색상 */
}
🎨전체코드::
<!--
============================================================
Blogger 자동 목차 생성 위젯 (Automatic Table of Contents Widget)
============================================================
[사용 방법]
1. 이 전체 코드를 복사합니다.
2. Blogger 대시보드에서 [테마] -> [HTML 편집]으로 이동합니다.
3. </body> 닫는 태그 바로 위에 이 코드를 붙여넣습니다.
4. (선택 사항) 사용 중인 테마에 따라 '.post-body' 선택자가 다를 수 있습니다.
만약 목차가 생성되지 않으면 JavaScript 코드 내의 'postBody' 변수 설정을
게시물 본문 영역의 정확한 CSS 선택자로 변경해야 합니다.
-->
<style>
/* ============================================================
목차 위젯 기본 스타일 (Custom Styles)
============================================================
/* 1. 전체 목차 컨테이너 스타일 */
#auto-toc-container.toc-box-style {
border: 1px solid #ddd;
/* margin: 20px 0; */ /* H2 위에 배치되므로 margin 조정이 필요할 수 있습니다. */
margin-bottom: 25px; /* 본문과 간격 */
background-color: #f7f7f7;
border-radius: 4px;
font-size: 16px;
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
}
/* 2. 토글 헤더 (Contents) 스타일 - 이미지의 회색 박스 */
.toc-toggle-header {
background-color: #fcfcfc;
border-bottom: 1px solid #ddd;
padding: 12px 15px;
cursor: pointer;
font-weight: bold;
color: #333;
display: flex; /* 아이콘과 화살표를 정렬 */
justify-content: space-between; /* 양 끝에 배치 */
align-items: center;
border-radius: 4px 4px 0 0;
}
/* 3. 리스트 아이콘 (☰) 스타일 */
.toc-icon-list {
margin-right: 10px;
font-size: 1.1em;
line-height: 1;
}
/* 4. 화살표 스타일 (오른쪽 정렬) */
.toc-arrow {
font-size: 1.1em;
font-weight: normal;
color: #555;
}
/* 5. 목차 내용 (리스트) 스타일 */
.toc-content-collapsible {
padding: 15px;
}
/* 6. 리스트 항목 스타일 */
.toc-content-collapsible ol {
padding-left: 20px;
margin-top: 5px;
margin-bottom: 5px;
}
/* 7. 계층별 리스트 스타일 */
.toc-list-level-1 {
/* 최상위 리스트 (H2) */
list-style-type: decimal; /* 1, 2, 3... */
}
.toc-list-level-2, .toc-list-level-3 {
/* 하위 리스트 (H3, H4) */
list-style-type: disc; /* •, o, ■ 등 */
margin-left: 15px;
}
.toc-content-collapsible a {
text-decoration: none;
color: #0073aa; /* 링크 색상 */
}
</style>
<script>
//<![CDATA[
// JavaScript를 이용한 자동 목차 생성 로직
function generateTOC() {
// 1. 블로그 게시물 본문 요소를 찾습니다.
const postBody = document.querySelector('.post-body') || document.querySelector('.entry-content') || document.querySelector('.post-content');
// 게시물 본문을 찾지 못하거나 목차 생성 제외 태그가 발견되면 종료
if (!postBody) return;
if (postBody.querySelector('.no-toc')) return;
// 2. H2, H3, H4 태그를 모두 찾습니다. (H1은 게시물 제목이므로 제외)
const headings = postBody.querySelectorAll('h2, h3, h4');
if (headings.length < 2) return; // 최소 두 개 이상의 제목이 있어야 목차를 생성합니다.
// 3. 목차(TOC) 컨테이너 및 토글 영역 생성 (이미지 모양 반영)
const tocContainer = document.createElement('div');
tocContainer.id = 'auto-toc-container';
tocContainer.className = 'toc-box-style'; // CSS 적용을 위한 클래스
// 3-1. 토글 헤더 영역 (Contents + Arrow) 생성
const tocToggle = document.createElement('div');
tocToggle.className = 'toc-toggle-header';
// 이미지처럼 'Contents'와 '>' 모양으로 시작
tocToggle.innerHTML = '<span class="toc-icon-list">☰</span> Contents <span class="toc-arrow">►</span>';
tocContainer.appendChild(tocToggle);
// 3-2. 목차 리스트 내용을 담는 컨테이너 생성
const tocContent = document.createElement('div');
tocContent.className = 'toc-content-collapsible';
tocContent.style.display = 'none'; // 초기 닫힘 상태
tocContainer.appendChild(tocContent);
// 최상위 리스트 (H2 레벨) 시작
let tocList = document.createElement('ol');
tocList.className = 'toc-list-level-1';
tocContent.appendChild(tocList);
let currentList = tocList;
let currentLevel = 2;
headings.forEach((heading, index) => {
const level = parseInt(heading.tagName.substring(1));
// 4. 고유 ID 생성 및 할당 (앵커 링크 연결을 위해 필수)
const headingId = 'toc-heading-' + (index + 1) + '-' + heading.textContent.replace(/[^a-z0-9]/gi, '').substring(0, 10).toLowerCase();
heading.id = headingId;
// 5. 계층 구조에 맞게 리스트 조정 (들여쓰기 로직 유지)
while (currentLevel < level) {
const newList = document.createElement('ol');
newList.className = `toc-list-level-${level}`;
if (currentList.lastChild) {
currentList.lastChild.appendChild(newList);
} else {
currentList.appendChild(document.createElement('li')).appendChild(newList);
}
currentList = newList;
currentLevel++;
}
while (currentLevel > level) {
currentList = currentList.parentNode.closest('ol');
if (!currentList) {
currentList = tocList;
break;
}
currentLevel--;
}
// 6. 목차 항목 (li) 생성 및 현재 리스트에 추가
const listItem = document.createElement('li');
const link = document.createElement('a');
link.href = '#' + headingId;
link.textContent = heading.textContent;
listItem.appendChild(link);
currentList.appendChild(listItem);
currentLevel = level;
});
// 8. 💡 수정된 부분: 토글 기능 추가 및 화살표 변경
tocToggle.addEventListener('click', function() {
const arrow = tocToggle.querySelector('.toc-arrow');
if (tocContent.style.display === 'none') {
tocContent.style.display = 'block';
arrow.innerHTML = '▼'; // 펼칠 때: ▼ (아래 화살표)
} else {
tocContent.style.display = 'none';
arrow.innerHTML = '►'; // 닫을 때: ▶ (오른쪽 화살표)
}
});
// 7. 💡 수정된 부분: 목차를 첫 번째 <h2> 태그 위에 삽입
const firstH2 = postBody.querySelector('h2');
if (firstH2) {
postBody.insertBefore(tocContainer, firstH2);
} else {
// H2가 없으면 (대안으로) 본문 맨 앞에 삽입
postBody.insertBefore(tocContainer, postBody.firstChild);
}
}
// 페이지 로드 후 generateTOC 함수를 실행합니다.
window.onload = function() {
setTimeout(generateTOC, 500);
};
//]]>
</script>
0 댓글