const generateToc = (target) => { if (target.length) { let toc = $('<section class="toc"></section>'), title = $('<h2 class="toc_title">toc<br>ー</h2>'), ul = $('<ul class="toc_list"></ul>'), html = toc.prepend(title), h2 = target.find('h2'), anchorName = 'section', text, childText; // - - // create list item // - - - - - - - - - const createItem = () => { for (let i = 0, len = h2.length; i < len; i++) { let child = $('<ul class="toc_child"></ul>'), anchorId = anchorName + i; $(h2[i]).attr('id', anchorId).nextUntil('h2').filter('h3').each((ci, cv) => { let anchorChildId = anchorId + '-' + ci; childText = $(cv).attr('id', anchorChildId).html(); $('<li class="toc_item-child"></li>').text(childText).appendTo(child).wrapInner(() => { return '<a class="toc_target" href="#' + anchorChildId + '"></a>'; }); }); text = $(h2[i]).html(); $('<li class="toc_item"></li>').wrapInner(() => { return '<a class="toc_target" href="#' + anchorId + '">' + text + '</a>'; }).appendTo(ul).append(child); } }; createItem(); // - - // insert toc // - - - - - - - - - const insertToc = () => { if (ul.find('li').length > 1) { html.append(ul); target.before(html); } }; insertToc(); // - - // toggle button // - - - - - - - - - - const clickBtn = () => { title.on('click', () => { toc.toggleClass('is-active'); ul.stop().slideToggle(250); }); }; clickBtn(); // - - // page scroll // - - - - - - - - - - const scroll = () => { toc.find('a').on('click', function(e) { let anchor = $(this.hash), time = 550, topDistance = 15, anchorOffset = anchor.offset().top - topDistance; $('html,body').animate({ scrollTop: anchorOffset }, { duration: time }, 'easeOutCubic'); }); }; scroll(); } }; generateToc($('#js-toc'));
<h1 class="h1">Generate toc from titles</h1> <div class="wrap"> <div class="inner" id="js-toc"> <section class="section"> <h2 class="h2">section 1</h2> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Enim quasi quos, quia officia, laborum aut ullam vitae aliquam tenetur rem libero, rerum consequuntur iusto odio vero odit porro perferendis error?</p> <h3 class="h3">child 1-1</h3> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quasi a veritatis porro soluta deleniti cum id pariatur aut voluptatibus, sint sunt reiciendis itaque excepturi asperiores minus nesciunt voluptates delectus labore!</p> <h3 class="h3">child 1-2</h3> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quasi a veritatis porro soluta deleniti cum id pariatur aut voluptatibus, sint sunt reiciendis itaque excepturi asperiores minus nesciunt voluptates delectus labore!</p> <h2 class="h2">section 2</h2> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt magnam velit, adipisci dolor, eius voluptate, animi suscipit cumque dicta blanditiis molestiae voluptatem molestias veritatis laborum autem odit laboriosam impedit non!</p> <h3 class="h3">child 2-1</h3> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quasi a veritatis porro soluta deleniti cum id pariatur aut voluptatibus, sint sunt reiciendis itaque excepturi asperiores minus nesciunt voluptates delectus labore!</p> <h2 class="h2">section 3</h2> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eum dolorem nam eos qui ab placeat optio vitae rem, deserunt incidunt consequatur animi quisquam natus quas, atque eligendi quasi accusantium esse!</p> <h3 class="h3">child 3-1</h3> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quasi a veritatis porro soluta deleniti cum id pariatur aut voluptatibus, sint sunt reiciendis itaque excepturi asperiores minus nesciunt voluptates delectus labore!</p> <h3 class="h3">child 3-2</h3> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quasi a veritatis porro soluta deleniti cum id pariatur aut voluptatibus, sint sunt reiciendis itaque excepturi asperiores minus nesciunt voluptates delectus labore!</p> <h2 class="h2">section 4</h2> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eum dolorem nam eos qui ab placeat optio vitae rem, deserunt incidunt consequatur animi quisquam natus quas, atque eligendi quasi accusantium esse!</p> <h3 class="h3">child 4-1</h3> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quasi a veritatis porro soluta deleniti cum id pariatur aut voluptatibus, sint sunt reiciendis itaque excepturi asperiores minus nesciunt voluptates delectus labore!</p> <h3 class="h3">child 4-2</h3> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quasi a veritatis porro soluta deleniti cum id pariatur aut voluptatibus, sint sunt reiciendis itaque excepturi asperiores minus nesciunt voluptates delectus labore!</p> </section> </div> </div> <link href="https://fonts.googleapis.com/css?family=Dancing+Script:400,700" rel="stylesheet">
body { width: 100%; min-height: 100vh; background-image: linear-gradient(60deg, #F7CAC9 15%, #91A8D0 85%); } p { text-align: justify; } .h1 { margin: 1.2em; font-family: 'Dancing Script', cursive; color: rgba(white, .85); } .h2 { font-size: 42px; font-family: 'Dancing Script', cursive; color: rgba(white, .85); } .h3 { font-size: 24px; font-family: 'Dancing Script', cursive; color: rgba(white, .85); } .wrap { display: flex; justify-content: center; align-items: center; } .inner { padding-right: 1em; padding-left: 1em; min-width: 300px; } .list { display: flex; } .item { font-size: 2em; + .item { margin-left: 2em; } } .section { max-width: 480px; padding: 1em; border: 6px double currentColor; } // toc // - - - - - - - - - - .toc { position: fixed; top: 1em; left: 1em; overflow: auto; padding: 1em; height: auto; max-height: calc(100vh - 2em); transition: .25s ease-out; border: 2px solid currentColor; opacity: .3; // &.is-active { background-color: rgba(#fff, .45); border-color: rgba(#000,0); box-shadow: 0 0 20px rgba(#000,.1); opacity: 1; } &:hover { opacity: 1; } } .toc_title { text-transform: uppercase; letter-spacing: .2em; cursor: pointer; } .toc_list { display: none; } .toc_item { text-transform: capitalize; letter-spacing: .1em; font-style: italic; font-size: 20px; // + .toc_item { margin-top: 1em; } } .toc_item-child { font-size: 14px; padding-left: 1em; }