-
ํฐ์คํ ๋ฆฌ์ ๋ชฉ์ฐจ (ToC) ๋ฃ๊ธฐ + ์์ ํ๊ธฐReview & How-to 2023. 1. 21. 01:29๋ฐ์ํ
๐ 5 mins read
์์ฐํ ํฐ์คํ ๋ฆฌ ์ด์ฉํ๊ธฐ..?๋๊น ๋ฆฌ๋ทฐ ์นดํ ๊ณ ๋ฆฌ์ ๋ฃ์ด๋ดค์ต๋๋ค.
๋ชฉ์ฐจ- ToC (Table of Contents) ์๋ ์ด๋ฐ ๊ธฐ๋ณธ ๊ธฐ๋ฅ์ด.. ํ๋ฌ๊ทธ์ธ์ ์๋ค๊ณ ..?
github pages ์ฐ๋ค๊ฐ pro ๊ณ์ ๋ง๋ฃ ๋ผ์ ์ด์ฐธ์ ์ฉ๋๋ ๋๋ํ๊ณ ์ค๋์ ๋ถํฐ ์ฐ๋ ํฐ์คํ ๋ฆฌ๋ก ๊ฐ์ํ์ผ์ง ํ๊ณ ์ฎ๊ฒผ๋๋ฐ,
15๋ ๋ ๋์ ๋ํ๋ฏผ๊ตญ ๋ํโค๏ธ ๋ธ๋ก๊ทธ ํ๋ซํผ์
๋ชฉ.์ฐจ. ๊ธฐ.๋ฅ.๋. ์.๋ค.์. (๋ณด๊ณ ์๋ ํฐ์คํ ๋ฆฌ??)๊ฒ์ ์ข ํด๋ณด๋ Tocbot ์ ๋ง์ด๋ค ์ด์ฉํ์๋ ๋ฏํ๋๊ตฐ์.
๋ง์นจ jekyll + github pages ์กฐํฉ์์๋ ์ฐ๋ tocbot ๋ชจ๋์ธ ๋ฐ๋ค, HTML ์คํจ ํธ์ง์ ์ ๊ณตํ๋ ํฐ์คํ ๋ฆฌ๋ผ์ ๊ฐ๋จํ๊ฒ ๊ฐ์ ธ์์ ๋ถ์ฌ ๋ดค์ต๋๋ค.๊ฐ๋ฐ์๊ฐ ์๋์ด๋ ์ ์ฉ ์์ฒด๋ ๊ฐ๋จํฉ๋๋ค. (๊ฐ๋จ? ํ ๊ฒ ๊ฐ์์)
1. ์์ค ๊ฐ์ ธ์ค๊ธฐ
Tocbot ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์คํฌ๋ฆฝํธ์ CSS๋ฅผ ๊ฐ์ ธ์์ผ ํฉ๋๋ค.
ํฐ์คํ ๋ฆฌ ์คํจ ํธ์ง > HTML ์์ ์์ <head> ํ๊ทธ ์์ ๋ค์๊ณผ ๊ฐ์ ๋ ์ค ์ถ๊ฐํด์ค๋๋ค.<!-- tocbot --> <script src="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.4.2/tocbot.min.js"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.4.2/tocbot.css">
2. ๋ชฉ์ฐจ๋ฅผ ์ฝ์ ํ ๊ณณ ์ง์ ํ๊ธฐ
Tocbot์ ๋์ ์ผ๋ก ์ฝํ ์ธ ๋ฅผ DOM parsing ํด์ ์์ฑํ๋ฏ๋ก, ๋ฏธ๋ฆฌ ๋ชฉ์ฐจ๊ฐ ์ฝ์ ๋ ์์น์ <div>๋ฅผ ์ฌ์ด ์ค์ผ ํฉ๋๋ค.
CSS์์์ ์๋์ ์์น๋ฅผ ์ด์ฉํ๊ธฐ ๋๋ฌธ์ ํฐ์คํ ๋ฆฌ์์๋ ๊ธ ๋ณธ๋ฌธ์ด ์์ํ๋ ๊ณณ์ด ์ข์ต๋๋ค.<div class="toc"></div> <!-- ์ผ๋ฐ --> <div class="toc hidden-xs hidden-sm"></div> <!-- ํ๋ธ๋ฆฟ, ๋ชจ๋ฐ์ผ์์ ์จ๊ธฐ๊ธฐ -->
- ํญ์ ์ฌ์ฉํ๋ ค๋ฉด ์ฒซ ๋ฒ์งธ ๊ธฐ๋ณธ ํด๋์ค๋ง ์ฌ์ฉ
- ๋ชจ๋ฐ์ผ์ด๋ ํ๋ธ๋ฆฟ์์๋ ํ๋ฉด์ด ์๋์ ์ผ๋ก ์์ผ๋ ๋ชฉ์ฐจ๋ฅผ ์์ ๊ณ ์ถ๋ค๋ฉด ๋ ๋ฒ์งธ ์ค์ ์ฌ์ฉ
์ฌ์ฉํ๋ ๊ธฐ๋ณธ ์คํจ/์ปค์คํ ์คํจ์ HTML ๋ง๋ค ๋ค๋ฅผ ํ ๋ฐ, ํฐ์คํ ๋ฆฌ ๊ธฐ๋ณธ ์คํจ์ด๋ผ๋ฉด <s_permalink_article_rep> ์ด๋ผ๋ ํ๊ทธ๋ก ์ผ์ด์ค๋ณ ๋ณธ๋ฌธ ์์น๋ฅผ ์ง์ ํ๊ณ ์์ต๋๋ค.
ํ. ๋์ผ๋ก HTML ์์ค ์ฝ๊ฒ ํ์
๋ชฉ์ฐจ ์ฝ์ ํ ์์น ์ฐพ๋ ๊ฒ์ ํฌํจํ์ฌ ์์ผ๋ก ์ธ๊ธํ , "์ฌ์ฉ ์ค์ธ ์คํจ๋ง๋ค ๋ค๋ฅผ ์ ์๋ ๋ถ๋ถ"์ ์ฐพ๋ ๊ฐ๋จํ ๋ฐฉ๋ฒ๋ ๋ฐฐ์๋ด ์๋ค. (๊ผญ ํฐ์คํ ๋ฆฌ๊ฐ ์๋์ด๋ ๋ด๊ฐ ๋ง๋ค์ง ์์ HTML์ ํธ์งํ ๋, ์์ค ํ์ํ๋๋ฐ ์ฉ์ดํฉ๋๋ค.)
ํฌ๋กฌ ๋ธ๋ผ์ฐ์ ์์ F12๋ฅผ ๋๋ฌ์ ์์ค ๋ณด๊ธฐ ๋ชจ๋๋ก ๋ค์ด๊ฐ๋๋ค.
(๋ค๋ฅธ ๋ธ๋ผ์ฐ์ ๋ผ๋ฉด ํฌ๋กฌ ๋ธ๋ผ์ฐ์ ๋ฅผ ์ฐ์ธ์.. ๋จ์ ๋ ๋ง์ง๋ง, ์ฅ์ ์ด ๋ ๋ง์ต๋๋ค ใ ใ )์๋ ๋นจ๊ฐ์ ๋๊ทธ๋ผ๋ฏธ๋ก ํ์ํด๋ ์์ด์ฝ์ ํด๋ฆญํ๋ฉด UI ๋ด์์ ๋ง์ฐ์ค๊ฐ ์ฌ๋ ค์ง ์์น์ ์์ค element ๊ฐ์ ๋ณผ ์ ์์ต๋๋ค.
์ด์ ๋ณธ๋ฌธ ์ ์ฒด๋ฅผ ๊ฐ์ธ๊ณ ์๋ <div>๋ฅผ ์ฐพ์์ฃผ๊ณ ๊ทธ ์ด๋ฆ์ ๊ธฐ์ตํ๋ฉด ๋ฉ๋๋ค.
3. Toc ๋์ ์คํฌ๋ฆฝํธ ์ถ๊ฐ
์ด์ body ํ๊ทธ์ ๋ค์ด๊ฐ Tocbot ์คํฌ๋ฆฝํธ๋ฅผ ์ถ๊ฐํด์ค๋๋ค.
์๋ ์ฝ๋์์ ".article_view"์ ํด๋นํ๋ ๋ช ์นญ์ ๋ชฉ์ฐจ๋ฅผ ํ์ฑํ๊ณ ์ ํ๋ ๋์์ด ๋๋ ๋ณธ๋ฌธ ํ๊ทธ์ธ๋ฐ, ์คํจ๋ง๋ค class๋ id ๋ช ์ด ๋ฌ๋ผ์ง๋ฏ๋ก ๋ณธ์ธ์ ์คํจ์์ content ๋ด์ง๋ article ํ๊ทธ๊ฐ ๋ฌด์์ธ์ง ํ์ธํ๊ณ ํด๋นํ๋ ๊ฐ์ผ๋ก ์ฑ์ ์ค์๋ค.
(Letter ์คํจ์ ๊ธฐ์ค์ผ๋ก ์์ฑ)<script> let content = document.querySelector('.article_view') let headings = content.querySelectorAll('h1, h2, h3, h4, h5, h6, h7') let headingMap = {} Array.prototype.forEach.call(headings, function (heading) { let id = heading.id ? heading.id : heading.textContent.trim().toLowerCase() .split(' ').join('-').replace(/[\!\@\#\$\%\^\&\*\(\):]/ig, '') 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', headingSelector:'h1, h2, h3', hasInnerContainers: false, collapseDepth: 3 }); $(document).ready(function(){ $('.toc').addClass('toc-absolute'); let toc_top = $('.toc').offset().top - 165; $(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> </s_t3> </body>
- ์ทจํฅ๊ป ์ต์
์ ๋ฃ๊ณ ๋นผ๊ณ ์์ ํ์ค ์ ์๊ฒ ๊ฐ๋จํ๋ง ๋ถ์ฐ์ค๋ช
์ ํ๋ฉด,
- Array.. ๋ heading์ id ์์ฑ์ด ์๋ ๊ฒฝ์ฐ์ ๋ํ ์ฒ๋ฆฌ๋ฅผ
- tocbot.init ๋ด์์ ํ๋ผ๋ฏธํฐ๋ก ์ต์
์ ์ถ๊ฐ๋ก ์ ์ดํ ์ ์๋๋ฐ, ์์ธ ์ต์
์ ์ฌ๊ธฐ์์
https://tscanlin.github.io/tocbot/#options - ์ฐธ๊ณ ๋ก collapseDepth ๋ h3 ๋ณด๋ค ํ์ ๋ชฉ์ฐจ๋ง ์จ๊ฒผ๋ค๊ฐ ํผ์น๋ ๊ธฐ๋ฅ์ธ๋ฐ, ๊ธฐ๋ณธ ๊ฐ์ 0์ผ๋ก ๋์ด์์ด์, h1 ์ธ์ ์ ๋ถ ์ ํ๋ ๊ฒ์ด ๊ธฐ๋ณธ ์ค์ ์ ๋๋ค. ๋ฉ๋ด๊ฐ ์ ๋ณด์ด๋ค๊ฐ ์คํฌ๋กค์ด ํด๋น ์ง์ ๊น์ง ๊ฐ๋ฉด ํ์ ๋ชฉ์ฐจ๊ฐ ํผ์ณ์ง๋ ๊ฒ์ด์ฃ .
4. CSS ์ถ๊ฐ
ํฐ์คํ ๋ฆฌ ๊ธฐ๋ณธ ์คํจ์ ๋ง๊ฒ ์ ๋นํ ์์น๋ ์คํ์ผ์ ์ง์ ํด ์ค๋๋ค.
(์คํจ ํธ์ง CSS์ ์ ๋นํ ์ถ๊ฐํด์ค๋๋ค.)๋ชฉ์ฐจ์ ๊ฐ๋ก ์์น๋ .toc.right์ ํตํด ๊ณ์ฐํ๊ณ ์์ผ๋ ์คํจ์ ๋ฐ๋ผ ๋ชฉ์ฐจ๊ฐ ๋ณธ๋ฌธ ์๋ก ์นจ๋ฒํ๋ค๋ฉด, ์์ ์ด ํ์ํ ์ ์์ต๋๋ค. (Letter๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ข์ฐ๋ก ์ฌ๋ฐฑ์ด ๊ดํํด์... ๊ทธ๋ฅ ์ฐ๋ฉด ๋ฉ๋๋ค)
/*tocbot*/ .toc-absolute { position: absolute; margin-top:165px; } .toc-fixed { position: fixed; top: 165px; } .toc { right: calc((100% - 850px) / 2 - 300px); width: 250px; padding: 10px; box-sizing: border-box; } .toc-list { margin-top: 10px !important; font-size: 0.9em; } .toc > .toc-list li { margin-bottom: 10px; } .toc > .toc-list li:last-child { margin-bottom: 0; } .toc > .toc-list li a { text-decoration: none; }
์์ฑ๋
์ ์ ์ฉ์ด ๋์๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ ๋ชฉ์ฐจ๊ฐ ์คํฌ๋กค๊ณผ ํจ๊ป ๋ฐ๋ผ๋ค๋๋๋ค.
# (๋ณด๋์ค) ๋ชฉ์ฐจ ํค๋ ์์ ํ๊ธฐ
๋ณธ๋ฌธ์ ์ ๋ชฉ(ํค๋)๋ฅผ ๋ฌ๋ฉด (โฌ๏ธ ์ ๋ ์ ์ฒ๋ผ์) ์๋์ผ๋ก TOC ์์ฑ ๋๋๊ฒ ๊น์ง ํ๋๋ฐ์.
์ ๋ชฉ์ ํญ์ ๋ฐ๋ฐํ๊ฒ ์์ฑํ์ง ์๊ณ ์์ "| ์ ๋ชฉ์ ๋๋ค", "# ์ ๋ชฉ์ ๋๋ค" ํน์ "[๋ง๋จธ๋ฆฌ] ์ ๋ชฉ์ ๋๋ค" ์ ๊ฐ์ด ํน์ ํจํด์ด๋ ์คํ์ผ๋ก ์์ฑํ๊ณ ์ถ์ ์ ๋ ์๊ฒ ์ฃ ?
์๋๋ฉด, ์ญ์ผ๋ก ์ ๋ชฉ์๋ ๊ทธ๋ฅ ๋ฌธ๊ตฌ๋ง ์์ฑํ๊ณ , ๋ชฉ์ฐจ๋ฅผ ์์ฑํ ๋ ๋ชฉ์ฐจ ๋งํฌ์ ์คํ์ผ์ ์ ํ๊ณ ์ถ์ ์๋ ์๊ฒ ๋ค์.
์์) "์ ๋ชฉ์ ๋๋ค" -> "โฝ๏ธ ์ ๋ชฉ์ ๋๋ค"
์ด๋ ๊ฒ ๋ณธ๋ฌธ์ ์์ฑ๋ ํค๋์ ์๋ ์์ฑ๋๋ TOC์ ๋ฌธ๊ตฌ๋ฅผ ๋ค๋ฅด๊ฒ ๊ฐ์ ธ๊ฐ๊ณ ์ถ์๋ ์๋์ ๊ฐ์ด toc ์ด๊ธฐํ ํจ์์ ํ๋ผ๋ฏธํฐ๋ก callback ํจ์๋ฅผ ํ๋ ์ถ๊ฐ ํด์ฃผ๋ฉด ๋ฉ๋๋ค.
tocbot.init({ tocSelector: '.toc', contentSelector: '.article_view', headingSelector:'h1, h2, h3', hasInnerContainers: false, collapseDepth: 3, ignoreHiddenElements: true, headingLabelCallback: function (heading) { return heading.trim().replace(/^#+\s?/, ''); } });
์์ "๋์ ์คํฌ๋ฆฝํธ ์ถ๊ฐ"์์ ํธ์งํ๊ฒ ์ฒ๋ผ ์คํจํธ์ง > HTML ํธ์ง > HTML ์์ค๋ณด๊ธฐ์์ ๋งจ ์๋์ tocbot.init() ํจ์ ํธ์ถ ํ๋๊ณณ์ ์์ ์ฝ๋์ ๊ฐ์ด headingLabelCallback ํ๋ผ๋ฏธํฐ๋ฅผ ์ถ๊ฐํด์ค๋๋ค.
์ ๋ ๋ฌธ์์ด heading์ ์ ๋ ฅ์ผ๋ก ๋ฐ์์, ๊ณต๋ฐฑ ์ ๊ฑฐํ, heading ์์ ๋ถ์ #๊ณผ ๊ณต๋ฐฑ์ ์ ๋ถ ์ ๊ฑฐํ๋ ํจ์๋ฅผ ์ถ๊ฐ ํ์ต๋๋ค.
์ด callback ํจ์๋ ๋ฌธ์์ด ์ ๋ ฅ์ ๋ฐ์์ ๋ฌธ์์ด๋ง ๋ฆฌํดํ๋ฉด ๋๋ ํจ์์ ๋๋ค. ์ฆ, ๋ณธ๋ฌธ์ ํค๋๋ฅผ ๋ฐ์์, TOC์ ์ค์ ๋ฃ์ ํ ์คํธ๋ฅผ ์ถ๋ ฅ ํด์ฃผ๋๊ฒ์ด์ฃ .์์ ์์ค๋ฅผ ์ถ๊ฐํ๋ฉด ์๋์ ๊ฐ์ด ์ ์ฉ๋ฉ๋๋ค. (link)
์ฐธ๊ณ ๋งํฌ
๋ฐ์ํ'Review & How-to' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
์์ธ๋ํ๊ต ๋ผ์ฟ ์น๋ ์์์ฅ ํ๊ธฐ (0) 2018.01.20