테마를 건드리지 않는 블로그 위젯 만들기: 목차, 진행 바, 댓글

Ghost 블로그에 목차·읽기 진행 바·댓글 위젯 세 개를 직접 만들어 붙이고, WordPress·Hugo·Tistory·Blogger에서까지 같은 코드로 동작하는지 확인한 과정을 정리했습니다.

Share
테마를 건드리지 않는 블로그 위젯 만들기: 목차, 진행 바, 댓글
Photo by Thought Catalog / Unsplash

GreedyLabs는 블로그를 self-hosted Ghost로 운영하고 있습니다. 글이 하나둘 길어지면서 목차가 아쉬웠고, 긴 글에는 지금 어디쯤 읽고 있는지 알려주는 표시가, 그리고 댓글이 있으면 좋겠다는 생각이 쌓였습니다.

흔한 방법은 테마 파일을 직접 고치거나 유료 위젯을 붙이는 것입니다. 하지만 테마를 건드리면 업데이트마다 깨질 걱정이 따라오고, 유료 서비스는 통제권을 남에게 넘기는 셈이라 쉽게 손이 가지 않았습니다. 정작 원한 건 코드 한 줄로 붙고, 테마와 절대 충돌하지 않으며, 마음에 안 들면 그 한 줄만 지우면 끝나는 가벼운 도구였습니다.

이 글은 그렇게 목차·읽기 진행 바·댓글 위젯 세 개를 직접 만들어 붙이고, Ghost를 넘어 WordPress·Hugo·Tistory·Blogger에서까지 같은 코드로 동작하는지 확인한 기록입니다. 자기 블로그에 작은 기능 하나를 가볍게 더하고 싶으신 분들께 참고가 되었으면 합니다.

전체 그림 한눈에 보기

먼저 큰 그림입니다. 세 위젯은 각각 목차(ghost-toc-plugin), 읽기 진행 바(ghost-progress-plugin), 댓글 위치 지정(ghost-giscus-plugin)을 담당하지만, 설계 원칙은 똑같습니다.

첫째, 테마에 의존하지 않습니다. 모든 클래스와 CSS 변수는 greedylabs-ghost-로 네임스페이스가 걸려 있어 어떤 테마와도 충돌하지 않습니다. 둘째, 설치는 코드 주입 한 번으로 끝납니다. 빌드 과정도, 테마 파일 수정도 없습니다. 셋째, jsDelivr CDN(@1 태그)으로 배포해 별도 호스팅이 필요 없고, 동작은 모두 스크립트 태그의 data- 속성으로 설정합니다. 셋 다 의존성 없는 순수 자바스크립트로 약 3KB입니다.

정리하면, 세 위젯의 개성은 다르지만 "테마를 건드리지 않고 한 줄로 붙는다"는 뼈대는 하나입니다. 이 뼈대가 나중에 플랫폼 독립성으로 이어집니다.

떠다니는 목차 만들기

ghost-toc-plugin은 본문의 h2, h3 제목을 읽어 화면 옆에 목차를 띄우고, 스크롤에 따라 현재 위치를 강조합니다. 화면이 좁아지면 자동으로 접혀서 본문을 가리지 않습니다.

손이 가장 많이 간 부분은 현재 섹션을 강조하는 로직이었습니다. 각 헤딩이 화면 상단 기준선에 닿는 스크롤 지점을 계산하는데, 글 끝부분의 헤딩들은 기준선에 영영 닿지 못하는 경우가 생깁니다. 그래서 닿지 못하는 꼬리 부분은 남은 스크롤에 고르게 나눠, 마지막 헤딩이 페이지 맨 끝에서 정확히 활성화되도록 했습니다. 이렇게 하지 않으면 글 끝의 여러 섹션이 강조되지 않고 넘어가 버리기 때문입니다.

색도 테마에 맡겼습니다. 목록 글자색 기본값은 Ghost Source 테마가 실제로 쓰는 보조 텍스트 토큰 --color-secondary-text를 따르게 했습니다. 덕분에 어느 테마에 붙여도 그 테마의 본문 색과 자연스럽게 어울리고, 필요하면 data-text로 원하는 색이나 CSS 토큰을 넣어 덮어쓸 수 있습니다.

읽기 진행 바 만들기

ghost-progress-plugin은 글을 얼마나 읽었는지 알려주는 얇은 바입니다. 진행률은 글 박스를 기준으로 계산합니다. 글 상단이 화면 위에 닿으면 0%, 글 하단이 화면 아래에 닿으면 100%가 되도록 했습니다. 화면 전체 스크롤이 아니라 글 자체를 기준으로 삼아야 머리말·꼬리말이 길어도 읽기 진행이 정확하기 때문입니다.

색은 기본적으로 테마 강조색(--ghost-accent-color)을 따르므로 별도 설정 없이도 사이트와 어울립니다. 최근에는 상단에 고정 내비게이션이 있는 사이트를 위해 data-anchor 옵션을 더했습니다. 선택자를 주면 화면 끝 대신 그 요소 아래(또는 위)에 바가 붙습니다. 다만 이 옵션은 데스크톱과 모바일에서 모두 안전해야 해서, 선택자가 비었거나 매칭되지 않거나 모바일에서 display:none으로 숨겨지면 자동으로 화면 끝으로 되돌아가게 했습니다.

정리하면, 진행 바는 "글을 기준으로 재고, 색과 위치는 테마에 맞추되, 없는 요소는 안전하게 넘어간다"는 세 가지를 지키는 것이 핵심이었습니다.

댓글을 원하는 자리에 놓기

ghost-giscus-plugin은 앞의 둘과 결이 조금 다릅니다. giscus는 이미 훌륭한 도구라 다시 만들 이유가 없었습니다. 그래서 이 플러그인은 giscus를 감싸거나 대체하지 않고, giscus가 댓글을 붙일 자리(.giscus 요소)만 원하는 위치에 만들어 줍니다. 본문 바로 뒤에 두거나, 테마의 기존 댓글 블럭을 그대로 대체할 수 있습니다.

여기서 한 가지 순서가 중요합니다. 이 플러그인 스크립트는 반드시 공식 giscus 스크립트보다 먼저 나와야 합니다. giscus는 실행되는 순간 자리를 확정하기 때문에, 우리 스크립트가 먼저 그 자리를 만들어 둬야 하기 때문입니다. 그리고 기준 요소를 찾지 못하면 페이지 가드가 giscus 스크립트를 제거해, 홈 화면 같은 곳에서 댓글이 엉뚱한 자리에 붙는 것을 막습니다.

핵심을 다시 짚으면, 잘 만들어진 것을 대체하는 대신 부족한 한 조각(위치 지정)만 채운 덕분에 코드가 작고 안정적이었습니다.

Ghost 밖에서도 되는지 확인하기

여기까지 만들고 보니, 세 위젯 모두 특정 플랫폼 API가 아니라 그냥 페이지에 스크립트 한 줄을 넣는 방식이라는 점이 눈에 들어왔습니다. 그렇다면 Ghost가 아니어도 HTML을 주입할 수 있는 곳이면 어디서든 동작해야 합니다. 그래서 데모를 다섯 군데에 직접 붙여 확인했습니다.

  • Ghost는 설정의 Code injection, Site Footer에 넣으면 끝입니다.
  • self-hosted WordPress는 헤더/푸터 삽입 플러그인이나 테마 footer.php의 닫는 앞에 넣습니다.
  • Hugo 같은 정적 사이트 생성기는 관리자 화면이 없으니 layouts/partials/footer.html 같은 템플릿에 넣고 다시 빌드합니다.
  • Tistory는 스킨 편집의 html 편집에서,
  • Blogger는 테마의 HTML 편집에서 앞에 붙입니다.

다섯 곳 모두 같은 스니펫으로 동작했습니다.

한 가지 조정이 필요합니다. 위젯이 본문을 찾는 data-content 선택자는 플랫폼과 테마마다 다릅니다. 기본값이 흔한 래퍼(.gh-content, article, main, .post-content, .entry-content)를 덮지만, 그래도 안 맞으면 위젯이 나타나지 않습니다. 그럴 때는 각 플러그인의 데모 페이지에서 data-content를 자기 테마의 본문 요소로 바꿔 스니펫을 다시 복사하면 됩니다.

정리하면, 테마를 건드리지 않겠다는 처음의 선택이 결국 플랫폼 독립성으로 돌아왔습니다. 코드 주입만으로 붙는 구조라, Ghost 전용으로 시작한 도구가 네 개의 다른 플랫폼에서 그대로 동작했습니다.

마치며

목차·읽기 진행 바·댓글 위치 지정, 세 위젯을 코드 한 줄로 붙는 형태로 만들고 다섯 플랫폼에 붙여 봤습니다.

바라는 것은 단순합니다. 더 많은 분들이 테마와 씨름하지 않고, 필요한 기능을 가볍게 더해 편안하게 블로그를 꾸리셨으면 합니다. 그래서 세 위젯 모두 MIT 라이선스로 공개하고 jsDelivr로 배포했습니다. 누구나 그대로 가져다 쓰고, 고치고, 더 나은 방향으로 함께 다듬어 주시면 좋겠습니다.

Plugins
Small, open-source plugins for Ghost that add common blog features with a single line of code injection. No theme editing, no build step, and nothing to self-host: each one loads from a CDN. All are MIT licensed. List of Plugins Every plugin below has a live demo where

소스와 데모, 설치 코드는 플러그인 소개 페이지에 모아 두었습니다. 도움이 되었다면 더할 나위 없겠고, 더 나은 방법이나 버그가 있으면 편하게 알려주세요.