path
Jin's Lab
코드로 실험하고 기록하는 개발 일지 · J.Lab

Jin's Lab

코드로 실험하고 기록하는 개발 일지. 커리어와 삶의 방향을 탐색하며 기록하는 공간입니다

blog-theme-customization

바닐라 JS 목차 생성으로 제이쿼리 없이 가볍고 빠른 TOC 만들기

J.Lab ·
목차

    최근 블로그 테마를 변경하면서 예상치 못한 문제를 마주했다. 본문 최상단의 대표 이미지가 자꾸 반복되거나 강제로 확대되어 화면을 꽉 채우는 현상 때문에 가독성이 심각하게 떨어졌다. 이 보기 싫은 문제를 해결하기 위해 이전에 쓰던 IT Story 테마의 깔끔한 목차 기능을 새로운 테마로 이식하기로 마음먹었다.

    하지만 이식하려는 새로운 jp- 계열 테마에는 결정적인 제약이 있었다. 기존 IT Story 테마의 목차 기능은 jQuery와 jquery.toc.js 플러그인에 무겁게 의존하고 있었는데, 새로 바꾼 테마에는 jQuery가 아예 내장되어 있지 않았다. 목차 하나 쓰자고 무거운 라이브러리를 추가하는 것은 비효율적이라고 판단해 가벼운 바닐라 JS 목차 생성 방법을 직접 구현하기로 결심했다.

    제이쿼리 대신 바닐라 자바스크립트 코드로 전환하는 개발 프로세스를 보여주는 아이소메트릭 일러스트레이션

    무거운 제이쿼리를 걷어내고 바닐라 JS를 선택한 이유

    웹사이트 성능 최적화가 중요해진 요즘, 제이쿼리 의존성을 줄이는 것은 성능 향상의 핵심 요소다. 기존의 jquery.toc.js는 편리하지만 브라우저 리소스를 불필요하게 소모한다는 단점이 있었다. 순수 자바스크립트로 코드를 재작성하면 용량이 획기적으로 줄어들고 로딩 속도가 빨라진다.

    내가 선택한 jp- 계열 테마의 가벼운 특성을 그대로 유지하기 위해서도 외부 라이브러리 없는 독립적인 코드가 필요했다. 가벼운 바닐라 JS 목차 생성 스크립트는 블로그의 첫 로딩 속도를 유지하면서도 내가 원하는 세부적인 제어 기능을 완벽하게 지원해 준다.

    헤딩 태그를 분석하여 한글 슬러그와 고유 ID 부여하기

    목차(table of contents)를 자동으로 생성하려면 먼저 포스트 본문 내에 위치한 제목 태그들을 정확히 찾아내야 한다. 새로운 테마의 구조를 분석해 보니 본문 영역은 `.jp-post-body` 클래스로 감싸져 있었다. 이 영역 안에서 h2, h3, h4 태그를 차례대로 스캔하도록 탐색 범위를 좁혔다.

    가장 까다로웠던 작업은 각 제목 태그에 고유한 ID를 부여하여 목차 링크와 매칭하는 과정이었다. 영문만 지원하는 단순한 슬러그 대신 한글 슬러그 생성이 완벽하게 동작하도록 정규식을 활용해 한글과 영문, 숫자가 포함된 고유 ID를 정제해 나갔다. 혹시 발생할 수 있는 동일한 제목의 중복 ID 문제를 방지하기 위해 중복 카운터를 더해 방어 코드도 철저히 심어두었다.

    본문 내 h2, h3, h4 헤더 태그들을 파싱하여 자동으로 정렬된 목차 구조로 변환하는 과정을 형상화한 일러스트

    부드러운 스크롤 이동과 헤더 오프셋 정밀 조절하기

    목차 아이템을 생성한 후에는 이를 클릭했을 때 본문 해당 위치로 매끄럽게 이동하도록 만들어야 한다. CSS의 기본 스크롤 동작 대신 자바스크립트의 smooth scroll 방식을 활용해 사용자 경험을 극대화했다. 목차 목록을 `ul`과 `li` 태그 조합으로 빌드하여 본문 상단에 동적으로 렌더링되도록 코드를 짰다.

    하지만 여기서 치명적인 문제가 발생했다. 테마 상단에 고정된 스티키 헤더(Sticky Header)가 목차 링크를 타고 이동한 실제 본문 제목을 가려버리는 현상이었다. 이를 해결하기 위해 각 제목 엘리먼트에 `scroll-margin-top` 속성을 동적으로 계산하여 오프셋 값을 제공함으로써, 헤더에 가려지지 않고 깔끔하게 멈추도록 조정했다.

    조건부 노출과 테마 맞춤형 디자인 완성하기

    모든 글에 제목 태그가 풍부하게 들어가는 것은 아니기 때문에, 짧은 글이나 헤딩이 없는 글에서는 목차 영역이 비어 있게 된다. 이런 군더더기를 방지하기 위해 본문을 스캔한 뒤 h2, h3, h4 태그가 하나도 존재하지 않을 경우 목차 레이아웃 전체를 자동으로 숨기도록 설계했다. 불필요한 영역이 화면을 차지하지 않으니 블로그 디자인이 한결 정돈되었다.

    마지막으로 jp- 계열 테마 고유의 컨셉 색상을 추출하여 목차의 테두리와 포인트 컬러에 고스란히 이식했다. 이렇게 구현된 바닐라 JS 목차 생성 스크립트는 기존의 무거웠던 제이쿼리 기반 목차보다 가벼우면서도 테마의 일부분인 것처럼 조화롭게 녹아들었다. 플러그인 없이 순수한 코드로 문제를 해결했을 때의 쾌감은 역시 대단하다.

    블로그 레이아웃에서 목차가 고정되어 부드러운 스크롤 효과와 함께 각 섹션을 동적으로 가리키는 디자인 예시
    blog-theme-customization javascript-toc table-of-contents vanilla-js web-performance
    ← 이전 글
    최근 게시물
    다음 글 →
    이전 게시물
    ≡ 글 목록으로
    소개
    path
    J.Lab

    커리어와 삶의 방향을 탐색하며
    기록하는 공간입니다

    카테고리
    403 Forbidden Error 1 AdSense 1 AdSense Bot Detection 1 AI Automation 1 AI Image Generation 1 ai-automation 2 AI-Prompting 1 AIBlogAutomation 1 AICodeLog 1 AIContentGeneration 1 AIImageGeneration 1 AIWritingErrors 1 API Automation 2 API Retry Design 1 api-automation 1 API-Deprecation 1 api-error 1 api-fallback 1 api-retry-strategy 1 api-troubleshooting 1 APIDebugging 1 APIError 1 APIErrorHandling 1 APIIntegration 1 APITokenRenewal 1 AppsScript 1 appsScriptAutomation 1 AutomatedBlogging 1 automation 1 Automation 2 AutomationTroubleshooting 1 Backoff Algorithm 1 Base64Encoding 1 BatchProcessing 1 blog-automation 1 blog-customization 1 blog-migration 3 Blog-Sorting 1 blog-strategy 1 blog-theme-customization 1 blog-workflow 1 blogautomation 1 BlogAutomation 2 Blogger 4 Blogger API 2 Blogger Automation 1 Blogger SEO 1 blogger-api 3 blogger-automation 1 blogger-error-400 1 blogger-labels 1 blogger-seo 1 blogger-tips 1 Blogger-Tips 1 BloggerAPI 3 BloggerBypath 1 BloggerCustomization 2 BloggerFavicon 1 BloggerTemplate 1 BloggerTemplateEditing 1 BloggerTheme 1 BloggerThemeCustomization 1 BloggerXMLStructure 1 Blogging-Automation 1 BloggingTools 1 BlogQuality 1 BlogSpot 1 BWidgetBIncludable 1 CardClickHandler 1 CDATA 1 clamping-text 1 Code Integration 1 codelog 1 CodeLog 1 codeRefactoring 1 contentsequencing 1 cost-reduction 1 CSSOverlay 1 data-parsing 1 DatabaseDesign 1 DataRecovery 1 DateInjection 1 Debugging 2 dev-journey 1 DeveloperJourney 2 DevJourney 1 display-none-seo 1 dom-manipulation 1 dynamic-menu 1 Error-Handling 1 ErrorHandling 1 Execution Timeout 1 ExecutionLimit 1 exponential-backoff 1 FactChecking 1 FaviconEmbedding 1 Feed-API 1 filesystem 1 Flat Illustration 1 FluxModel 1 FreeAIImage 1 FrontEndDev 1 FrontendTips 1 GAS Blogger API 1 gas-automation 1 gas-optimization 1 gas-trigger 1 GASTimeout 1 gasTriggerManagement 1 GCP Project Linkage 1 Gemini 1 Gemini API 1 gemini-api 1 GeminiAPI 1 GeminiPrompt 1 GeminiPromptEngineering 1 GmailRestrictions 1 Google Apps Script 7 Google Discover 1 google-apps-script 3 Google-Apps-Script 1 google-blogger 1 googleAppsScript 1 GoogleAppsScript 6 googlesapps-script 1 hero-image 1 HTMLWidgetBlogger 1 http-429 1 HuggingFace 1 HuggingFaceAPI 1 ico-generator 1 Image Optimization 1 image-automation 1 image-optimization 1 In-App Browser 1 invalid-argument 1 javascript 3 JavaScript 2 javascript-automation 1 javascript-toc 1 jlab-codelog 1 JLabDevLog 1 json-schema 1 label-length-limit 1 linux 1 meta-description 1 Negative Prompt 1 notion-api 1 notion-database 1 notion-gas-integration 1 NotionAPI 1 NotionAutomation 1 notionintegration 1 NotionIntegration 1 OAuth Scope 1 pagination 1 payload-validation 1 permalink-management 1 PersonaDesign 1 pil-image-processing 1 Pinterest 1 Pollinations 1 Pollinations Flux 1 pollinations-api 1 PollinationsAI 1 PositionAbsolute 1 Prompt Design 1 Prompt Engineering 1 prompt-engineering 1 Prompt-Engineering 1 PromptEngineering 1 publishorder 1 python-favicon 1 queue-stuck 1 RandomDelay 1 rate-limiting 1 Refactoring 1 rfc3339 2 Robots Meta Tag 1 RSS Feed 1 scriptNotFound 1 Search Engine Optimization 2 Search-Engine-Optimization 1 SEO Tips 1 seo-optimization 4 SEO-Optimization 1 seriesmanagement 1 SidebarLinks 1 SNSMarketing 1 SVGIcon 1 table-of-contents 1 TechJournal 1 Template 1 ThreadsAPI 1 tistory-migration 1 transparent-favicon 1 triggerCleanup 1 Troubleshooting 1 unzip 1 URL Slug 1 vanilla-js 1 Web Development 1 Web Publishing 2 Web Security 1 web-development 1 Web-Development 1 web-development-tips 1 web-performance 1 web-scraping 1 WebAccessibility 1 WebDevelopment 3 WebDevelopmentTips 1 WebDevJourney 1 windows 1 WorkflowAutomation 1 XMLParser 1 XMLSpecialCharacters 1 XMLTheme 1 zip 1
    인기 글
    GAS에서 Blogger API 403 오류 완전 정복 — appsscript.json 스코프와 GCP 프로젝트 연결
    GAS에서 Blogger API 403 오류 완전 정복 — appsscript.json 스코프와 GCP 프로젝트 연결
    Google Apps Script 실행 시간 6분 제한 — Gmail 계정 함정과 랜덤 딜레이 설계
    Google Apps Script 실행 시간 6분 제한 — Gmail 계정 함정과 랜덤 딜레이 설계
    Blogger 테마 XML 직접 뜯어봤더니 알게 된 것들
    Blogger 테마 XML 직접 뜯어봤더니 알게 된 것들
    다른 블로그
    IssueLog
    IssueLog
    issuelog.jinbytes.com
    KidStory
    KidStory
    kidstory.jinbytes.com
    IT Story
    IT Story
    jinbytes.com
    © Jin's Lab · J.Lab · All Rights Reserved
    jinbytes.com · Powered by Blogger