ブログを読んでいるときに「あれ、いま自分が読んでる見出しってなんだっけ・・・?」って、見失いがちじゃないですか?
僕はよくあります。
集中して読んでない証拠です。てへぺろ。
目次まで戻るのもひと手間ですし、長文になればなるほど迷子になりやすいです。
そこで僕は、スクロールに合わせて現在表示中の見出し(H2)をヘッダー下に出す仕組みをこのブログに実装してみました。
参考までに、この記事ではその実装手順をコピペしやすいコード付きでまとめます。
テーマ改造に慣れていない方でも、出来るだけつまずかない順番で進めますね。
実装手順とコードをご紹介

まどろっこしいのは面倒なので、まず最初に手順とコードをご紹介します。
※バックアップを保存して自己責任にて実装してください。
手順1:footer.php に HTML+JavaScript をまとめて追加
まずは footer.phpの </body>直前にコードを入れます。
管理画面 → 外観 → テーマファイルエディター → footer.php
THE THORの親テーマにfooter.phpがありました。
管理画面の「外観 → テーマファイルエディター」から footer.php を開きます。
そして、ファイルの下の方にある </body> の直前へ、下のコードを貼り付けてください。
固定ヘッダーか、そうじゃないかでコードが変わります。
管理画面 → 外観 → カスタマイズ → 共通エリア設定[THE] → ヘッダーエリア設定 →■ヘッダーを固定表示するか選択
ここで変更できます。
footer.phpに貼り付けるコード@固定ヘッダー版
////////////////// H2見出し固定化 //////////////////
<div id="current-heading-bar">
<span class="current-heading-label">現在の見出し:</span>
<span class="current-heading-text"></span>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
/* 1. ヘッダー高さから offset を計算 */
const header =
document.querySelector('.headerFix') ||
document.querySelector('#header') ||
document.querySelector('.l-header');
let offset = 0;
if (header) {
offset += header.offsetHeight;
}
document.documentElement.style.setProperty('--header-offset', offset + 'px');
/* 1.5 投稿/固定ページどちらかの本文コンテナの位置・幅を取得 */
const content =
document.querySelector('.postContents') ||
document.querySelector('.pageContents');
const setContentRect = () => {
if (!content) return;
const rect = content.getBoundingClientRect();
document.documentElement.style.setProperty('--content-left', rect.left + 'px');
document.documentElement.style.setProperty('--content-width', rect.width + 'px');
};
setContentRect();
/* 2. H2見出し & 終端マーカー取得 */
const bar = document.getElementById('current-heading-bar');
if (!bar) return;
const labelText = bar.querySelector('.current-heading-text');
const headings = Array.from(
document.querySelectorAll(
'.postContents h2.wp-block-heading, .pageContents h2.wp-block-heading'
)
);
if (!headings.length) {
bar.style.display = 'none';
return;
}
const endMarkers = Array.from(document.querySelectorAll('.heading-end-marker'));
let endPos = Infinity;
const recalcEndPos = () => {
if (!endMarkers.length) {
endPos = Infinity;
return;
}
const lastMarker = endMarkers[endMarkers.length - 1];
endPos = lastMarker.getBoundingClientRect().top + window.scrollY;
};
/* 2.5 各H2のスクロール位置を保持 */
let positions = [];
const recalcPositions = () => {
positions = headings.map(h => h.getBoundingClientRect().top + window.scrollY);
recalcEndPos();
};
recalcPositions();
/* 3. 現在の見出しを判定 */
const updateCurrentHeading = () => {
const current = window.scrollY + offset + 1;
if (current < positions[0]) {
bar.classList.remove('is-visible');
return;
}
if (current > endPos) {
bar.classList.remove('is-visible');
return;
}
let activeIndex = 0;
for (let i = 0; i < positions.length; i++) {
if (positions[i] <= current) activeIndex = i;
else break;
}
const text = headings[activeIndex].textContent.trim();
labelText.textContent = text || '';
bar.classList.add('is-visible');
};
/* 初期表示 */
updateCurrentHeading();
/* 4. スクロール & リサイズ時も更新 */
window.addEventListener('scroll', updateCurrentHeading);
window.addEventListener('resize', () => {
recalcPositions();
setContentRect();
updateCurrentHeading();
});
window.addEventListener('load', () => {
recalcPositions();
setContentRect();
updateCurrentHeading();
});
});
</script>
footer.phpに貼り付けるコード@固定ヘッダーじゃない版
////////////////// H2見出し固定化 //////////////////
<div id="current-heading-bar">
<span class="current-heading-label">現在の見出し:</span>
<span class="current-heading-text"></span>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
/* 1. ヘッダー高さから offset を計算 */
const header =
document.querySelector('.headerFix') ||
document.querySelector('#header') ||
document.querySelector('.l-header');
let offset = 0;
document.documentElement.style.setProperty('--header-offset', offset + 'px');
/* 1.5 投稿/固定ページどちらかの本文コンテナの位置・幅を取得 */
const content =
document.querySelector('.postContents') ||
document.querySelector('.pageContents');
const setContentRect = () => {
if (!content) return;
const rect = content.getBoundingClientRect();
document.documentElement.style.setProperty('--content-left', rect.left + 'px');
document.documentElement.style.setProperty('--content-width', rect.width + 'px');
};
setContentRect();
/* 2. H2見出し & 終端マーカー取得 */
const bar = document.getElementById('current-heading-bar');
if (!bar) return;
const labelText = bar.querySelector('.current-heading-text');
const headings = Array.from(
document.querySelectorAll(
'.postContents h2.wp-block-heading, .pageContents h2.wp-block-heading'
)
);
if (!headings.length) {
bar.style.display = 'none';
return;
}
const endMarkers = Array.from(document.querySelectorAll('.heading-end-marker'));
let endPos = Infinity;
const recalcEndPos = () => {
if (!endMarkers.length) {
endPos = Infinity;
return;
}
const lastMarker = endMarkers[endMarkers.length - 1];
endPos = lastMarker.getBoundingClientRect().top + window.scrollY;
};
/* 2.5 各H2のスクロール位置を保持 */
let positions = [];
const recalcPositions = () => {
positions = headings.map(h => h.getBoundingClientRect().top + window.scrollY);
recalcEndPos();
};
recalcPositions();
/* 3. 現在の見出しを判定 */
const updateCurrentHeading = () => {
const current = window.scrollY + offset + 1;
if (current < positions[0]) {
bar.classList.remove('is-visible');
return;
}
if (current > endPos) {
bar.classList.remove('is-visible');
return;
}
let activeIndex = 0;
for (let i = 0; i < positions.length; i++) {
if (positions[i] <= current) activeIndex = i;
else break;
}
const text = headings[activeIndex].textContent.trim();
labelText.textContent = text || '';
bar.classList.add('is-visible');
};
/* 初期表示 */
updateCurrentHeading();
/* 4. スクロール & リサイズ時も更新 */
window.addEventListener('scroll', updateCurrentHeading);
window.addEventListener('resize', () => {
recalcPositions();
setContentRect();
updateCurrentHeading();
});
window.addEventListener('load', () => {
recalcPositions();
setContentRect();
updateCurrentHeading();
});
});
</script>
手順2:追加CSSを登録(見た目 & 幅調整)
次は見た目をCSSで整えます。
管理画面 → 外観 → カスタマイズ → 追加CSS
WordPress管理画面で、外観 → カスタマイズ → 追加CSSを開きます。
そこに、以下のCSSをコピペしてください。
追加CSSに貼り付けるコード
/******************************
画面上部に固定表示する「現在の見出し」バー
*******************************/
/* 見出しバーの終点マーカー(見た目は消す) */
.postContents .heading-end-marker {
height: 0;
margin: 0;
padding: 0;
border: none;
}
#current-heading-bar {
position: fixed;
/* ★合計値 = ヘッダー高さ + 任意微調整 */
top: calc(var(--header-offset, 0px) + var(--login-adjust, 0px));
left: 0;
right: 0;
z-index: 9999;
padding: 8px 16px;
font-size: 14px;
background: rgba(225, 225, 225, 0.96);
backdrop-filter: blur(4px);
border-bottom: 1px solid #eee;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
display: flex;
align-items: flex-start;
gap: 4px;
box-sizing: border-box;
opacity: 0;
pointer-events: none;
transition: opacity 0.2s;
}
#current-heading-bar.is-visible {
opacity: 1;
pointer-events: auto;
}
.current-heading-label {
font-weight: 600;
opacity: 0.7;
flex-shrink: 0;
}
/* ★「…」で省略せず、折り返して全部見せる */
.current-heading-text {
font-weight: 600;
white-space: normal; /* 折り返しOK */
overflow: visible; /* はみ出しOK */
text-overflow: clip; /* 省略記号を使わない */
line-height: 1.4;
}
/* バーと本文が被らないように、少しだけ余白を足す(必要に応じて調整) */
.postContents,
.pageContents {
padding-top: 56px; /* ヘッダー+バーの高さを見ながら増減してOK */
}
/* PC表示では .postContents の幅&位置に合わせる */
@media (min-width: 1024px) {
#current-heading-bar {
left: var(--content-left, 0px);
right: auto;
width: var(--content-width, auto);
}
}
手順3:記事末尾へ「終端マーカー」を配置
記事の終了を感知するタグを設置します。
管理画面 → 外観 → カスタマイズ → ウィジェット → 投稿ページ下部エリア → カスタムHTML
カスタムHTMLに貼り付けるコード
<div class="heading-end-marker"></div>
これが無いと、記事が終わって下にスクロールしてフッターなどを表示している場合でも、最後の見出しが表示されたままになります。
あとは保存して完了です。
気に入らない部分は、お好みでカスタマイズしてください。
なぜ「現在の見出し表示」があると読みやすいの?
結論から言うと、「いまどこを読んでいるか」を迷わなくなるからです。
記事が長くなればなるほど、見出し間の移動や“話の位置”が分かりにくくなって、結果的に何が言いたいかが分かりにくい気がします。
だからこそ、スクロール中にいまの見出しが常に見えるだけで、「読み進める安心感」が生まれます。
内容が良くても、読みづらいと面倒になって離脱することもありますよね。
「現在の見出し表示」は派手な機能ではないですが、読見やすさを底上げする、小さな改善ではないでしょうか。
まとめ:個人的に読みやすくなった気がする
今回は、THE THOR環境で「いま読んでいるH2見出しをヘッダー下に表示する」仕組みを実装する流れをまとめました。
見た目は地味なんですが、読者の“いまどこ?”を解消できるので、体感の読みやすさがグッと上がる気がします。
今回の手順をもう一度おさらい

やったことは大きく3つだけでした。
- 手順①:footer.php の
</body>直前にコードを追加
※固定ヘッダーか、そうじゃないかでコードが変わる - 手順②:追加CSSにコードを追加
- 手順③:投稿ページ下部エリアにカスタムHTMLウィジェットを追加
ちなみに、今回のコードはほぼ全てChatGPTにお願いして作ってもらいました。
どやっ
かがくの ちからって すげー
AIを使うと、こういったプログラミングもサクッとできるので本当に楽ですね。
こういう小さな工夫を積み重ねて、読みやすくて良いブログにしていきたいです。
ぜひ試してみてくださいね。


コメントを書く