サイドバーに現在位置を表示して追尾する目次を設置する【Ver3】

いわゆるシングルページナビゲーションみたいなやつ。(2018/05/03更新)

できること

  • サイドバーに目次を設置
  • スクロールすると追尾する
  • 現在位置の背景色変更
  • リンク先へのスムーズスクロール
  • ウィンドウサイズ変更に合わせてサイズ変更
  • 記事ページ以外でもページ内の記事一覧などを表示

動作環境

  • サイドバーが横に表示されるテーマ
  • 親要素にtransformがないテーマ

動作確認はPC版のChromeFireFox、Edge、IE11で行っています。
※設定によってはスマホタブレットでも動きますが基本的にPC向けです。

前バージョンからの主な変更点

  • ウィンドウサイズ変更に対応
  • 使えるテーマが増えた

他にもCSSのIDとクラス名が変わったり、jQuery使うのをやめたりと変更点が多いです。

その他の変更履歴

インストール

念のため追加する前の設定は保存しておきましょう。

HTML

デザイン設定の[カスタマイズ]-[サイドバー]-[モジュールを追加]-[HTML]に貼り付ける。
タイトルはスクリプトが読み込まれた段階でスクリプト側で指定したものに置き換えられます。

JavaScript

デザイン設定の[カスタマイズ]-[フッタ]に追加する。
(上のHTMLの後に追記しても動きます)

CSS

デザイン設定の[カスタマイズ]-[デザインCSS]に追加する。

文字色(2018/04/22追記)

デフォルトではページに設定されたリンクの色が使われますが、変更したい場合はCSSに下記を追加します。

#stoc a {
  color: #カラーコード;
}
/* 訪問済みのリンクの色(一色だけにしたい場合は指定しない) */
#stoc a:visited {
  color: #カラーコード;
}

設定について

スクリプトの冒頭部分を変更することである程度動作を変えられます。そのままでも動きますがテーマや好みに応じて変更してください。
trueはオン、falseはオフみたいな意味で他の部分も全て半角で書きます(目次タイトルは全角も使える)。

ここで説明するもの以外についてはこちら→ その他の設定値

メディアクエリ(重要)

変数名 デフォルト
MATCH_MEDIA false
MEDIA_QUERY_SIDEBAR '(min-width: 768px)'

デフォルトではサイドバー要素が横に表示されているかを#box2要素のfloatプロパティがnoneかどうかで判定しています。
(正確にはgetComputedStyle(document.getElementById('box2')).cssFloatの結果がnoneかどうか。floatがない場合もnoneが返される)

しかしBoilerplateを元に作られたテーマなどはfloatが使用されていないためこの方法では判別できないので、かわりにメディアクエリを使います。

MATCH_MEDIAtrueMEDIA_QUERY_SIDEBARにサイドバーが表示されるページ幅の条件などを書きます。この値はテーマによって違うのでChromeなどでF12を押すと出るデベロッパーツールでbox2要素などに適用されているスタイルから@media (min-width: 768px)みたいな物がないか調べましょう(説明がつらい)。
ちなみにデフォルトで入ってる'(min-width: 768px)'だと「ページの横幅が768px以上」ならサイドバーが表示されているという意味になります。

目次を表示するページ

記事ページでは普通に見出し一覧を表示しますが、トップページやアーカイブページでは記事タイトル一覧を目次として表示できます。

デフォルトでトップページやアーカイブページでも表示するように設定されていますが、必要無い場合はpage-indexpage-archivedisplayfalseに変更してください。

  {
    class    : 'page-index',
    title    : 'このページの記事一覧',
    listPage : true,
    display  : false  // ここをtrueからfalseに
  },
  {
    class    : 'page-archive',
    title    : 'このページの記事一覧',
    listPage : true,
    display  : false  // ここをtrueからfalseに
  },

設定を変えればタイトルの変更やPro機能の固定ページでも表示できます。
詳しくはこちら→ PAGES options

表示する見出しタグ

変数名 デフォルト
HEADLINE_QUERY ['h3', 'h4', 'h5']

目次に表示したい見出しタグを指定します。数字が小さい順に書いてください。

固定時の余白

変数名 デフォルト
MARGIN_TOP 10
MARGIN_BOTTOM 0

目次モジュールが固定(追尾)される時の上下の余白を指定できます。

グローバルメニュー

変数名 デフォルト
GLOBAL_HEADER ['#globalheader-container']
  • 追尾開始位置を正しく取得するために、ヘッダーメニュー・グローバルメニュー等と呼ばれる常時表示・追尾型のメニュー(上に表示されるもの)のidclassを指定します
  • idの場合は#classの場合は.を先頭に書いてください
  • classを指定して複数の要素が見つかった場合でも先頭の要素だけを対象にします
  • 複数指定する場合は['#globalheader-container', '.global-menu']のようにコンマで区切って書きます
  • Pro版でヘッダを非表示にしている場合はデフォルトの'globalheader-container'は消しても大丈夫ですが[]は残してください
  • 目次と重なる時はMARGIN_TOPを調整します

見出し位置などの更新(2018/05/03追記)

変数名 デフォルト
CLICK_UPDATE []
CLICK_UPDATE_DELAY 500

現在位置表示用の見出し位置や目次の追尾開始位置などはロードが終わった時やウィンドウサイズ変更後に取得していますが、他の要因で高さが変わるとずれてしまいます。
このオプションで指定された要素をクリックすると見出し位置などの更新が行われるので、クリックによる目次の開閉などで高さが変わってもずれないように出来ます。

  • CLICK_UPDATEに指定する要素の書き方は上のGLOBAL_HEADERと同じ
    ただしclassを指定した場合は見つかった全ての要素が対象になります。
  • CLICK_UPDATE_DELAYは要素クリック後の更新を遅らせる時間
    アニメーションの時間などを考慮して調整してください。

たとえば['.archive-module-hide-button', '.archive-module-show-button']と指定すると、サイドバーの「月別アーカイブ」モジュールの開閉ボタンをクリックした後に更新され、目次の追尾開始位置のずれを防げます。

スムーズスクロール

変数名 デフォルト
SCROLL_TIME 400
SCROLL_TIME_TOUCH 0
  • スムーズスクロールにかける時間をミリ秒で指定できます(TOUCHが付いてる方はタッチデバイスでのスクロール時間)
  • 0にするとスムーズスクロールはオフになります

HTML構造

色が薄い所ははてなブログ側で用意される部分です。
nav#stocはインストール時に貼り付けたHTML)

f:id:Twilyze:20180301042610p:plain

追尾中#stoc-moduleに付与されるクラスの条件

  • tracking ウィンドウかページに固定している時
    • fixed ウィンドウに固定している時
    • absolute ページに固定(下までスクロール)している時
  • fade-in 他のサイドバーモジュールより上に設置していて追尾開始した時

仕様と注意点

  • 見出しが設定値より少ない・表示する設定にしていないページの時はモジュール全体を非表示にします
  • 目次記法による目次が表示されていない時のページ内リンクはsection0, section1...になります
  • 目次やメニューの開閉などでページの高さが後から変わったりすると現在位置表示はずれます
    ※追記(2018/05/03) CLICK_UPDATEオプションである程度対応可能 解説↑
  • 沢山サイドバーモジュールを設置していると見づらいので置き過ぎには注意しましょう

タッチデバイスでの動作

レスポンシブデザインモードやPro機能、「PC版サイト表示」などをしない限りあまり関係ない話。

スマホなどタッチデバイスでのスクロール処理はPCと違うので追尾が不自然になったりします。これを解決するためにタッチデバイスの時はposition:stickyIE11未対応)を使っているのですが、そのために以下の処理が入ります↓

  • #stoc-module#stoc.touchクラスを追加
  • ブラウザがposition:stickyに対応していれば#stoc-module.stickyクラスを追加
    • サイドバーモジュールの親要素#box2-innerの高さを記事部分#main-innerの高さと合わせる

#box2-innerの高さを変更した影響でテーマによっては見た目が変になりますが仕様です。

こんなときは

デザイン・色が合わない

テーマによっては追尾中に背景色がなくなるなどの症状が出ます。

簡易的ですが以下の公式テーマ向けのCSS例→ カスタマイズ例

  1. Aero
  2. Afternoon
  3. ヨミカキ by kanahei
  4. Popcorn by カタノトモコ
  5. Report
  6. レトロポップ
  7. Skull wings
  8. Solid
  9. Terminal
  10. Venetia

目次の上下に白いグラデーションが表示される

ページの縦幅よりも目次が大きい時にスクロールバーとさらにスクロール可能かを分かりやすくするためのオプション機能(SCROLL_SHADOW)があるんですが、
f:id:Twilyze:20180115011054p:plain
デフォルトでは白い背景色に合うように設定されているのでテーマに合わせて変更する必要があります。

[デザインCSS]に追加した以下の部分を

  • /* Shadows */の下に2つあるrgba(0,0,0,.17)(透明度のある黒)を表示したい色
  • /* Shadow covers */の下に2つある#fff(真っ白)を背景色と同じ色

にそれぞれ設定します

/* sidebar_toc.css */
#stoc.shadow {
  /* Shadows */
  background:
    radial-gradient(farthest-side at top, rgba(0,0,0,.17), transparent) top / 100% 11px,
    radial-gradient(farthest-side at bottom, rgba(0,0,0,.17), transparent) bottom / 100% 11px;
}
#stoc.shadow > ol {
  /* Shadow covers */
  background:
    linear-gradient(#fff 30%, transparent) top / 100% 40px,
    linear-gradient(transparent, #fff 70%) bottom / 100% 40px;
}

この表示自体いらない場合は設定部分のSCROLL_SHADOWfalseにしてください。

フッタに空の要素が表示される

フッタにスクリプトを書いた影響でテーマによっては空の#bottom-editarea要素が表示されます。非表示にしたい場合は[デザインCSS]に以下を追加してください。

#bottom-editarea {
  display: none;
}

フッタに他の要素がある場合動作がおかしくなるかも知れないので注意。

もしくはフッタではなくHTMLを書いた場所に追記しても動きます。たぶん。

追尾する位置になると画面外に消える

親要素にアニメーション等でtransformが使われているとposition:fixedが上手く動かなくなり表示できません。

position:fixedが効かない事件簿 - Qiita

position:stickyを使うモードにすると治る可能性があります(F_STICKY_MODE)。たぶん。
親要素にoverflow:hiddenがあると動かないので注意。

なにかいい方法があるかも知れませんが基本的に親要素にtransformは使用しないでください。

あとがき

まさかの大型バージョンアップ3回目。もうここまで大きな更新はしない(はず)。

なるべく分かりやすいように作りたかったけど分かりづらいですね申し訳ない。各自頑張って…。
正直標準の公式テーマ対応するだけで力尽きたので他のテーマだとおかしいかも。


要望やバグ報告はコメント欄かGoogleフォームの方へどうぞ。
ただし対応できるかは分からないのであまり期待しないでお待ち下さい。

参考