実現したいこと
スクロールすると右側の目次が追従し、sectionごとに目次部分が切り替わるような仕様を作りたいです。
section1にいる場合は目次「①」に背景色が加わり、そのsectionの見出し文が表示されるような感じです。
section2以降にスクロールした場合は、目次「①」の背景色と見出し文がなくなり、「②」の背景色と見出し文が表示されるような仕様です。
発生している問題・分からないこと
https://www.bring-flower.com/blog/fixed-and-highlighted-toc/
BringFlowerさんのコードを参考にしました。
olタグの幅を縮めて無理やり縦書きにして、上記のようなものを実現しようと試みましたが、上手くいきません。
JavaScriptにまだまだ乏しく、どのように書けば再現できますでしょうか?
どうかよろしくお願いします。
該当のソースコード
html、css、JavaScript
1<meta name="robots" content="noindex,nofollow" /> 2<!doctype html> 3<html lang="ja"> 4 5<head> 6 <meta charset="UTF-8" /> 7 <meta name="viewport" content="width=device-width, initial-scale=1" /> 8 <link rel="stylesheet" href="https://plot-hub.com/code_example/lib/css/reset.css"> 9 10 <style media="screen"> 11 section.toc-demo{ 12 margin: 0 auto; 13 } 14 h2{ 15 font-size: 20px; 16 background-color: #f3f3f3; 17 border-bottom: 3px solid #333; 18 padding: 5px 0 5px 10px; 19 } 20 p{ 21 padding-left: 10px; 22 } 23 ol{ 24 width: 43px; 25 position: fixed; 26 top: 4vh; 27 right: 25px; 28 } 29 li{ 30 list-style-type:none; 31 } 32 a{ 33 display: block; 34 width: 100%; 35 color: #fff; 36 margin-bottom: 1px; 37 text-decoration: none; 38 padding: 3px 5px 3px 10px; 39 } 40 a.current{ 41 background-color: #dd5eb3; 42 color: #000; 43 writing-mode: vertical-rl; 44 -webkit-writing-mode: vertical-rl; 45 -moz-writing-mode: vertical-rl; 46 -ms-writing-mode: tb-rl; 47 -ms-writing-mode: vertical-rl; 48 } 49 .top{ 50 width: 100%; 51 height: 70vh; 52 background-color: #fbb03b; 53 } 54 .writing-mode{ 55 writing-mode: vertical-rl; 56 -webkit-writing-mode: vertical-rl; 57 -moz-writing-mode: vertical-rl; 58 -ms-writing-mode: tb-rl; 59 -ms-writing-mode: vertical-rl; 60 } 61 62 .content{ 63 width: 100%; 64 height: 100vh; 65 } 66 .toc-demo .content:nth-child(2){ 67 background: #8cc63f; 68 } 69 .toc-demo .content:nth-child(3){ 70 background: #0092ff; 71 } 72 </style> 73</head> 74 75<body> 76 <section class="top">TOP</section> 77 <section class="toc-demo"> 78 <div class="content"> 79 <h2 class="h2test">見出し1</h2> 80 </div> 81 <div class="content"> 82 <h2 class="h2test">見出し2</h2> 83 </div> 84 <div class="content"> 85 <h2 class="h2test">見出し3</h2> 86 </div> 87 <div class="content"> 88 <h2 class="h2test">見出し4</h2> 89 </div> 90 <div class="content"> 91 <h2 class="h2test">見出し5</h2> 92 </div> 93</section> 94 95 <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> 96 <script type="text/javascript"> 97 const headings = document.querySelectorAll('.h2test'); 98let toc = '<ol id="fixed-toc">'; 99 100headings.forEach( function(heading, index) { 101 heading.id = 'heading-0' + (index+1); 102 let id = heading.id; 103 toc = toc + '<li><a href="#' + id + '">' + heading.textContent + '</a></li>'; 104}); 105 106toc = toc + '</ol>'; 107document.querySelector('.toc-demo').insertAdjacentHTML('afterbegin', toc); 108 109window.addEventListener('scroll', function() { 110 let scroll = window.scrollY;//スクロール量を取得 111 let hight = window.innerHeight;//画面の高さを取得 112 let offset = 400;//どの時点で現在表示されている見出しとするかの調整値 113 const toc_completed = document.getElementById('fixed-toc'); 114 115 headings.forEach( function( heading , index) { 116 let i = index + 1; 117 let target = document.querySelector('#fixed-toc li:nth-of-type(' + i + ') > a'); 118 let pos = heading.getBoundingClientRect().top + scroll;//見出しの位置 119 120 if ( scroll > pos - hight + offset ) {//スクロール量が見出しを超えた 121 122 if (headings[index + 1] !== undefined){// 次の見出しがある=最後の見出しではない 123 124 let next_pos = headings[index + 1].getBoundingClientRect().top + scroll;//次の見出しの位置 125 if ( scroll > next_pos - hight + offset ) { // スクロール量が次の見出しも超えている 126 target.classList.remove('current'); 127 } else if (target.classList.contains('current') == true) { // すでにcurrentがついている 128 return; 129 } else if ( i == 1 && toc_completed.classList.contains('active') == false ){// 1つ目 130 target.classList.add('current') 131 toc_completed.classList.add('active') 132 } else { // 次の見出しは見えてない 133 target.classList.add('current'); 134 } 135 136 } else { //最後の見出しの時 137 target.classList.add('current'); 138 } 139 } else { //スクロール量が見出しを超えてない 140 target.classList.remove('current'); 141 if ( i == 1 && toc_completed.classList.contains('active')){ //1つ目に到達していない場合 142 toc_completed.classList.remove('active') 143 } 144 } 145 }); 146}); 147 </script> 148 149 150 151</body> 152 153</html> 154
試したこと・調べたこと
- teratailやGoogle等で検索した
- ソースコードを自分なりに変更した
- 知人に聞いた
- その他
上記の詳細・結果
JavaScript内のheading.textContentが見出し文だと思うのですが、だけ表示するには新たにif文を加えていけばいいのでしょうか?
目次の数字は見出しには書かないようにしたいのですが、いまいちやり方がわかりません...。
補足
特になし

回答2件
あなたの回答
tips
プレビュー