티스토리 사이드 목차(TOC) 추가하기

2022. 6. 18. 22:44개발/이야기

 TOC가 모아~ 떄다놘 싸뢈두리쥐~

사랑합니다. 선생님 (출처)

개요

TOC. Table Of Content의 약자로 콘텐츠 제목들을 테이블 리스트 형식으로 주욱 나열한 걸 말한다.

티스토리 보다는 회사 Notion 이나 개인 Notion에 글을 쓸 일이 많았다.

이전에는 몰랐는데, 노션에 회의록을 작성하거나 위키를 작성할 때 어김없이 필요했던 것이 목차이다.

velog에서는 사이드 목차 기능이 있는데 티스토리에는 따로 없기 때문에 tocbot이라는 오픈소스를 이용해서 목차를 만들었다.

2020년 8월 이후 업데이트가 없지만 망가지면 고쳐 쓰지 모 ㅎㅎ

과정

1. html 테마 편집

테마 편집 화면으로 접속한다.

블로그 관리 → 꾸미기 → 스킨 편집 → html 편집

2. tocbot 불러오기

먼저 <head> 안에서 tocbot을 불러온다. css와 js 파일을 모두 가져와야 하니 <link> <script> 태그를 사용하자.

...
<!-- TOC -->
<link
  rel="stylesheet"
  href="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.11.1/tocbot.css"
/>
<script
  type="module"
  src="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.11.1/tocbot.min.js"
></script>
...

공식 document에는 <script> 태그를 넣을 때 따로 module 설정을 해주지 않는데,
이렇게 불러오게 되면 tocbot에서 사용하는 스코프와 다른 모듈에서 가져온 스코프가 겹칠 수 있으므로
module을 추가해서 가져오자. (갑분 module 관련 설명글)

3. tocbot 설정

다음은 페이지가 로드될 때 tocboth1 ~ h3까지의 태그를 잘 읽어와서 보여줄 수 있도록 설정해준다.

<script type="module">
  const content = document.querySelector(".article_view"); // 본인 블로그 content class
  const headings = content.querySelectorAll("h1, h2, h3");
  const headingMap = {};

  Array.prototype.forEach.call(headings, function (heading) {
    const id = heading.id
      ? heading.id
      : heading.textContent
          .trim()
          .toLowerCase()
          .split(" ")
          .join("-")
          .replace(/[\!\@\#\$\%\^\&\*\(\):]/gi, "");
    headingMap[id] = !isNaN(headingMap[id]) ? ++headingMap[id] : 0;
    if (headingMap[id]) {
      heading.id = id + "-" + headingMap[id];
    } else {
      heading.id = id;
    }
  });

  tocbot.init({
    tocSelector: ".toc",
    contentSelector: ".article_view", // 본인 블로그 content class
    headingSelector: "h1, h2, h3",
    activeLinkClass: "toc-active", // scroll시 toc active 색깔 변경
    collapseDepth: 3,
    hasInnerContainers: false,
  });

  $(".toc").addClass("toc-not-scrolled");

  const toc_top = $(".article_view").offset().top - 200;
  $(window).scroll(function () {
    if ($(this).scrollTop() >= toc_top) {
      $(".toc").addClass("toc-fixed");
      $(".toc").removeClass("toc-not-scrolled");
    } else {
      $(".toc").addClass("toc-not-scrolled");
      $(".toc").removeClass("toc-fixed");
    }
  });
</script>

이때 우리는 저 <script>를 어디에 두어야 할까?

<head> 안이라고 생각한다면 땡! 틀렸다.

이 스크립트는 <head>에 있는 tocbot이 잘 불러와진 다음 DOM이 생성된 이후에 불려야 한다.

따라서 <body> 태그 마지막에 넣어주면 된다.

4. css 추가

위에서 설정했던 toc 관련 custom css를 추가한다.

css편집은 html 편집 우측에서 가능하다.

/* TOC */
.toc-not-scrolled {
  position: fixed;
  top: 600px;
}

.toc-fixed {
  position: fixed;
  top: 165px;
}

.toc {
  right: 10%;
  max-width: 250px;
  padding: 10px;
  box-sizing: border-box;
  transition: top .5s, right .5s;
}

.toc-list {
  margin-top: 14px !important;
  font-size: 0.9em;
}

.toc > .toc-list li {
  margin-bottom: 14px;
}

.toc > .toc-list li:last-child {
  margin-bottom: 0;
}

.toc > .toc-list li a {
  text-decoration: none;
}

.toc-active.toc-active::before {
  background-color: #4B89DC;
}

@media(max-width: 1500px){
  .toc {
     right: 2rem;
  }
}

@media(max-width: 1180px){
  .toc {
     display: none;
  }
}

미디어 쿼리를 사용해서 ipad air 기준인 1180px 까지만 toc를 지원하고 이후에는 보이지 않도록 설정했다.

background-color 나 얼마나 우측 또는 좌측에 사이드 목차를 둘 건지는 조금씩 조정해서 보기 편한 블로그를 만들면 끝!

사알짝 꼼수이긴 한데 css 선택자 우선순위에 따라서 .toc-active.toc-active::before 라고 설정하면 우선순위가 높아져서 important를 사용하지 않아도 된다.

같은 클래스 이름을 붙여서 사용함으로써 자기 자신을 조금 더 높은 우선순위로 접근할 수 있다.