幅781px以下で画面右下に表示する、手動リンク方式の追従目次です。
detailsとsummaryで開閉でき、JavaScriptはリンク選択後とEscapeキーで閉じる処理を補助します。
旧版の端末判定・隠したチェックボックス・全アンカーへの処理は使いません。
動く見本
スマートフォン幅では右下の「この記事の目次」を開けます。
PC幅では表示しません。
この見本は本記事内の「設置方法」「確認と戻し方」へ移動します。
自動的に見出しを抽出する機能ではありません。
この記事の目次
設置方法
変更前に対象記事の本文と、追加先のCSS・JavaScriptの内容を保存します。
旧mobile_toc_widgetやfoot_customtagsを導入済みなら、その設置場所も控え、旧目次と今回の目次を併用しないようにします。
対象記事のカスタムHTMLブロックへHTMLを1組だけ置きます。
リンク先の各見出しにブロック設定のHTMLアンカーを指定し、hrefの値と一致させます。
同じIDを複数の見出しに付けないでください。
見出しを追加・削除したりHTMLアンカーを変更したりした場合は、目次側のリンクも手動で更新します。
<details class="waza-mobile-toc">
<summary>この記事の目次</summary>
<nav aria-label="この記事の目次"><ul>
<li><a href="#waza-toc-install">設置方法</a></li>
<li><a href="#waza-toc-check">確認と戻し方</a></li>
</ul></nav>
</details>
CSSは子テーマのスタイルシートなどへ追加します。
wp_is_mobileによる出し分けは行わず、画面幅で表示するため、PC向けHTMLがキャッシュされてもHTML自体は共通です。
.waza-mobile-toc { display: none; }
@media (max-width: 781px) {
.waza-mobile-toc {
display: block; position: fixed; right: 12px;
bottom: calc(12px + env(safe-area-inset-bottom));
z-index: 90; width: min(300px, calc(100vw - 24px));
background: #fff; color: #222; border: 2px solid #766028;
border-radius: 8px; box-shadow: 0 2px 12px #0002;
}
.waza-mobile-toc summary { padding: 12px; cursor: pointer; font-weight: bold; }
.waza-mobile-toc nav { max-height: 50vh; overflow-y: auto; padding: 0 12px 12px; }
.waza-mobile-toc a { display: block; padding: 8px; color: #173b65; }
.waza-mobile-toc :focus-visible { outline: 3px solid #173b65; outline-offset: 2px; }
}
JavaScriptは対象ページで1回読み込みます。
JSファイルへ置く場合はscriptタグを付けません。
カスタムHTMLへ入れる場合のみscriptタグで囲み、保存後に削除されていないか確認します。
掲載コードは初期化時点の目次とリンクに処理を登録します。
Pjaxや別のスクリプトが後から追加した目次・リンクへ自動的に登録し直す処理はありません。
(() => {
const init = () => document.querySelectorAll('.waza-mobile-toc').forEach(toc => {
const summary = toc.querySelector('summary');
if (!summary || toc.dataset.wazaReady) return;
toc.dataset.wazaReady = '1';
toc.addEventListener('keydown', event => {
if (event.key === 'Escape' && toc.open) {
toc.open = false; summary.focus(); event.preventDefault();
}
});
toc.querySelectorAll('a[href^="#"]').forEach(link => link.addEventListener('click', () => {
let id; try { id = decodeURIComponent(link.hash.slice(1)); } catch { return; }
const target = document.getElementById(id);
if (!target) return;
toc.open = false;
if (!target.hasAttribute('tabindex')) target.setAttribute('tabindex', '-1');
target.focus({preventScroll: true}); // スクロール自体は標準のアンカー移動
}));
const media = matchMedia('(max-width: 781px)');
media.addEventListener('change', () => {
if (!media.matches) toc.open = false;
});
});
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init, {once: true});
else init();
})();
確認と戻し方
スマホ幅で開閉、リンク先への移動、TabとEnter・Space、Escapeで閉じてsummaryへフォーカスが戻ることを確認します。
これは非モーダルな目次なので、開いている間もページ内のほかの要素を操作できます。
details自体の開閉と通常のアンカーリンクが動いても、JavaScriptが正しく読み込まれた証拠にはなりません。
Escapeで閉じる動作と、リンク選択後に目次が閉じて見出しへフォーカスが移る動作も分けて確認してください。
780px前後だけでなく781pxと782px、横向き、ブラウザーの拡大でも確認してください。
テーマの固定ヘッダーに見出しが隠れる場合は、見出し側のscroll-margin-topを実際のヘッダー高さに合わせます。
Cookie表示や他の固定ボタンとの重なりも設置先で調整します。
実端末のタッチ操作、読み上げ、すべてのテーマ・広告・最適化プラグインとの組み合わせは未検証です。
戻すときは今回のHTML・CSS・JavaScriptを外します。
旧mobile_toc_widgetやfoot_customtagsとは併用せず、旧コードの設置場所を控えてから切り替えます。
旧ウィジェット方式と旧外部コード集は今回の見本と未同期です。




