FE 개발노트/etc

[티스토리 커스텀] 01. TOC 목차 띄우기

미스터코다리 2021. 9. 26. 19:14

TOC 만들기

프스팅 목적

  • 글을 읽을 때 화면에 고정된 목차 링크 TOC를 만들어보자
  • TOC는 h1,h2 와 같은 헤더를 읽어 목차를 만든다. 따라서 글을 작성할 때 마크다운 모드로 작성하여야 한다.
  • Tocbot을 이용해 티스토리의 스킨에 삽입하는 것 자체에 목적이 있다.
  • 더 좋은 코드, 적절한 커스텀에 대한 포스팅은 후에 작성될 예정이다.

TOC가 필요해

벨로그로 가고싶은 가장 큰 이유 중 하나가 글 내부에 고정되어 바로 이동할 수도 있는 목차였다. 티스토리도 언젠가 기능을 추가해주길 기다리면서.. Tocbot이라는 플러그인을 적용시켰다. jquery 없이 순수 바닐라 자바스크립트로 구성된 모듈이다.

toc 이란 Table Of Contents 의 약자로, 마크다운으로 작성한 글의 헤더 태그들을 모아 목차로 보여주는 것이다.

README에 잘 나와 있으니 모듈 적용에 무리가 없는 개발자들은 Tocbot github에서 바로 확인하면 된다. 이번 포스팅은 티스토리의 특정 스킨을 이용해서 toc를 넣고 싶은 비개발자를 위해 한땀한땀 적어보려 한다.

Tistory + Tobcot 라이브러리 사용

1. 스킨 선택

블로그관리 → (꾸미기) 스킨 변경

가장 깔끔하고 후에 커스텀도 용이해보이는(딱히 꾸며진 것이 없고 글과 목차만 반응형으로 보여주는) 반응형1 스킨을 선택했다. 이번 포스팅엔 대단한 커스텀이 없기 때문에 우측 여백이 없는 스킨만 아니면 어떤 것을 선택해도 무방할 것 같다.

2. Tocbot 기본 세팅

블로그관리 → (꾸미기) 스킨 편집
좌측 상단의 html 편집을 누르면 html, css 코드를 편집할 수 있다.
우측은 적용된 결과를 보는 페이지로 우측 상단의 홈, 글, 방명록 등 페이지마다의 스타일 적용 상태를 확인할 수 있다.

헤더 영역에 넣기 (CSS)

<!-- Tocbot -->
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.11.1/tocbot.css">
<!-- Tocbot -->

바디 가장 하단에 넣기 (JS)

<!-- Tocbot -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.11.1/tocbot.min.js"></script>
<!-- Tocbot -->

toc 가 들어갈 위치에 div 생성

저 곳이 글읽기로 들어갔을 때 보여지는 곳이다. hidden-xs 와 hidden-sm는 티스토리에서 작은 사이즈의 스크린일 때 보여주지 않기 위해 넣은 것이다.

<s_permalink_article_rep>
    <div class='toc hidden-xs hidden-sm testing'></div>
...
</s_permalink_article_rep>

위까지 마치면 당연히 아무것도 나오지 않는다. tocbot.init에 적절한 도큐먼트 요소들을 지정해주지 않았기 때문이다. 원활한 작업을 위해 testing 클래스를 추가하여 자리를 잘 찾고 있는지만 확인해주자. 아래의 스타일을 css 코드 하단에 추가하면 toc이 들어갈 자리에 빨간 테두리가 뜨는 것을 볼 수 있다.

.testing{
    border: 1px solid red;
    min-width: 10px;
    min-height: 10px;
}

최소 높이, 최소 넓이를 주고 빨간색 테두리로 확인했다. 가로가 화면 전체를 자리잡고 있는걸 보니 블럭 요소가 아닌가보지만, 어디있는지 확인만하는 용이니 무시하자. 나중에 작업이 끝날 때 testing은 지울 것이다.

3. Tocbot 코드 넣기

CSS 코드

주의사항 : 우리의 Tocbot은 넓은 화면일 때만 보여야하기 때문에 @media only screen and (max-width:820px) 와 같은 작은 화면용 스타일 블럭에 넣으면 안된다. 그냥 제일 밖, 마지막에 두면 된다.

/* Tocbot */
.toc-absolute{
    position: absolute;
    margin-top: **250px**;
}

.toc-fixed{
    position: fixed;
    top: **180px**;
}

.toc {
    right: calc((100% - **840px**) / 2 - 300px);
    width: 250px;
    padding: 10px;
    box-sizing: border-box;
}
.toc-list {
    font-size: 0.9rem;
    text-overflow:ellipsis;
}
.toc > .toc-list li {
    margin-bottom: 10px;
}
.toc > .toc-list li:last-child {
    margin-bottom: 0;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
}
.toc > .toc-list li a {
    text-decoration: none;
}

js 로 동작시키기 (body 하단)

한번 쓰고 말 세팅 관련 요소들은 즉시 실행 함수로 처리하는 등 조금이라도 더 봐줄만한 코드로.. 하긴 했는데... 시간이 날 때 toc 커스텀을 제대로 해볼 예정

<script>
//Tocbot
  (function ($) {
  const content = document.querySelector('.postContent');
  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: '.postContent',
  headingSelector: 'h1, h2, h3',
  hasInnerContainers: false,
});

$(document).ready(function () {
  $('.toc').addClass('toc-absolute');

  const toc_top = $('.toc').offset().top - 200;
  console.log(toc_top);
  $(window).scroll(function () {
    if ($(this).scrollTop() >= toc_top) {
      $('.toc').addClass('toc-fixed');
      $('.toc').removeClass('toc-absolute');
    } else {
      $('.toc').addClass('toc-absolute');
      $('.toc').removeClass('toc-fixed');
    }
  });
});
</script>

tocbot.init 에 넣어줄 매개변수는 tocbot을 초기화할 때 필요한 기본적인 정보들을 담은 객체다.

toSelector 에 우리가 toc을 생성할 클래스를, contentSelector엔 h1,h2,h3 들을 찾아내는 범위에 해당하는 div 클래스를 지정해주면 된다. 이 예제에서는 postContent라고 해주고

<div class="area_view postContent">
                    



            

TOC 만들기

프스팅 목적

  • 글을 읽을 때 화면에 고정된 목차 링크 TOC를 만들어보자
  • TOC는 h1,h2 와 같은 헤더를 읽어 목차를 만든다. 따라서 글을 작성할 때 마크다운 모드로 작성하여야 한다.
  • Tocbot을 이용해 티스토리의 스킨에 삽입하는 것 자체에 목적이 있다.
  • 더 좋은 코드, 적절한 커스텀에 대한 포스팅은 후에 작성될 예정이다.

TOC가 필요해

벨로그로 가고싶은 가장 큰 이유 중 하나가 글 내부에 고정되어 바로 이동할 수도 있는 목차였다. 티스토리도 언젠가 기능을 추가해주길 기다리면서.. Tocbot이라는 플러그인을 적용시켰다. jquery 없이 순수 바닐라 자바스크립트로 구성된 모듈이다.

toc 이란 Table Of Contents 의 약자로, 마크다운으로 작성한 글의 헤더 태그들을 모아 목차로 보여주는 것이다.

README에 잘 나와 있으니 모듈 적용에 무리가 없는 개발자들은 Tocbot github에서 바로 확인하면 된다. 이번 포스팅은 티스토리의 특정 스킨을 이용해서 toc를 넣고 싶은 비개발자를 위해 한땀한땀 적어보려 한다.

Tistory + Tobcot 라이브러리 사용

1. 스킨 선택

블로그관리 → (꾸미기) 스킨 변경

가장 깔끔하고 후에 커스텀도 용이해보이는(딱히 꾸며진 것이 없고 글과 목차만 반응형으로 보여주는) 반응형1 스킨을 선택했다. 이번 포스팅엔 대단한 커스텀이 없기 때문에 우측 여백이 없는 스킨만 아니면 어떤 것을 선택해도 무방할 것 같다.

2. Tocbot 기본 세팅

블로그관리 → (꾸미기) 스킨 편집
좌측 상단의 html 편집을 누르면 html, css 코드를 편집할 수 있다.
우측은 적용된 결과를 보는 페이지로 우측 상단의 홈, 글, 방명록 등 페이지마다의 스타일 적용 상태를 확인할 수 있다.

헤더 영역에 넣기 (CSS)

<!-- Tocbot -->
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.11.1/tocbot.css">
<!-- Tocbot -->

바디 가장 하단에 넣기 (JS)

<!-- Tocbot -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.11.1/tocbot.min.js"></script>
<!-- Tocbot -->

toc 가 들어갈 위치에 div 생성

저 곳이 글읽기로 들어갔을 때 보여지는 곳이다. hidden-xs 와 hidden-sm는 티스토리에서 작은 사이즈의 스크린일 때 보여주지 않기 위해 넣은 것이다.

<s_permalink_article_rep>
    <div class='toc hidden-xs hidden-sm testing'></div>
...
</s_permalink_article_rep>

위까지 마치면 당연히 아무것도 나오지 않는다. tocbot.init에 적절한 도큐먼트 요소들을 지정해주지 않았기 때문이다. 원활한 작업을 위해 testing 클래스를 추가하여 자리를 잘 찾고 있는지만 확인해주자. 아래의 스타일을 css 코드 하단에 추가하면 toc이 들어갈 자리에 빨간 테두리가 뜨는 것을 볼 수 있다.

.testing{
    border: 1px solid red;
    min-width: 10px;
    min-height: 10px;
}

최소 높이, 최소 넓이를 주고 빨간색 테두리로 확인했다. 가로가 화면 전체를 자리잡고 있는걸 보니 블럭 요소가 아닌가보지만, 어디있는지 확인만하는 용이니 무시하자. 나중에 작업이 끝날 때 testing은 지울 것이다.

3. Tocbot 코드 넣기

CSS 코드

주의사항 : 우리의 Tocbot은 넓은 화면일 때만 보여야하기 때문에 @media only screen and (max-width:820px) 와 같은 작은 화면용 스타일 블럭에 넣으면 안된다. 그냥 제일 밖, 마지막에 두면 된다.

/* Tocbot */
.toc-absolute{
    position: absolute;
    margin-top: **250px**;
}

.toc-fixed{
    position: fixed;
    top: **180px**;
}

.toc {
    right: calc((100% - **840px**) / 2 - 300px);
    width: 250px;
    padding: 10px;
    box-sizing: border-box;
}
.toc-list {
    font-size: 0.9rem;
    text-overflow:ellipsis;
}
.toc > .toc-list li {
    margin-bottom: 10px;
}
.toc > .toc-list li:last-child {
    margin-bottom: 0;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
}
.toc > .toc-list li a {
    text-decoration: none;
}

js 로 동작시키기 (body 하단)

한번 쓰고 말 세팅 관련 요소들은 즉시 실행 함수로 처리하는 등 조금이라도 더 봐줄만한 코드로.. 하긴 했는데... 시간이 날 때 toc 커스텀을 제대로 해볼 예정

<script>
//Tocbot
  (function ($) {
  const content = document.querySelector('.postContent');
  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: '.postContent',
  headingSelector: 'h1, h2, h3',
  hasInnerContainers: false,
});

$(document).ready(function () {
  $('.toc').addClass('toc-absolute');

  const toc_top = $('.toc').offset().top - 200;
  console.log(toc_top);
  $(window).scroll(function () {
    if ($(this).scrollTop() >= toc_top) {
      $('.toc').addClass('toc-fixed');
      $('.toc').removeClass('toc-absolute');
    } else {
      $('.toc').addClass('toc-absolute');
      $('.toc').removeClass('toc-fixed');
    }
  });
});
</script>

tocbot.init 에 넣어줄 매개변수는 tocbot을 초기화할 때 필요한 기본적인 정보들을 담은 객체다.

toSelector 에 우리가 toc을 생성할 클래스를, contentSelector엔 h1,h2,h3 들을 찾아내는 범위에 해당하는 div 클래스를 지정해주면 된다. 이 예제에서는 postContent라고 해주고

<div class="area_view postContent">
        
</div>

티스토리 스킨에서 글 본문 영역에 해당하는 div를 찾아 (이번 스킨에서는 area_view) postContent 클래스를 추가해줬다.

마무리

TOC를 넣기는 했지만 마음에 딱 맞는 좋은 코드로 커스텀하지 못하여서 마음이 안좋다. 심지어 또한 H1 태그를 남발하게 되어 매우 마음이 불편하다. (H1 헤더는 한 페이지에 하나가 원칙이다.)티스토리 기본 스킨에 맞춰 본문의 제목태그 순서 및 스타일을 커스텀하는 시간을 꼭 가져야겠다.

to be continue...

커스텀 예정

  • 본문의 h1 태그 스킨 전체 구조에 맞게 재설정
  • toc가 푸터 영역 침범하지 않도록 수정
  • 더 좋은 코드로 리팩토링

참고링크

</div>

티스토리 스킨에서 글 본문 영역에 해당하는 div를 찾아 (이번 스킨에서는 area_view) postContent 클래스를 추가해줬다.

마무리

TOC를 넣기는 했지만 마음에 딱 맞는 좋은 코드로 커스텀하지 못하여서 마음이 안좋다. 심지어 또한 H1 태그를 남발하게 되어 매우 마음이 불편하다. (H1 헤더는 한 페이지에 하나가 원칙이다.)티스토리 기본 스킨에 맞춰 본문의 제목태그 순서 및 스타일을 커스텀하는 시간을 꼭 가져야겠다.

to be continue...

커스텀 예정

  • 본문의 h1 태그 스킨 전체 구조에 맞게 재설정
  • toc가 푸터 영역 침범하지 않도록 수정
  • 더 좋은 코드로 리팩토링

참고링크