SANGOで現在の見出しを上部に追従させるサルワカ風カスタマイズ

サルワカさんをよく利用されている方は気付いていると思いますが、記事をスクロールして読み進めていくと、「今読んでる章の見出し」が画面上にずーっとくっついてきますよね?

あれを付けたいなーと前から思っていたので、実践してみました。

完成後の動作イメージはこんな感じ。

コピペ用コード

まず最初に全体のコードをご紹介しますね。

  • SANGO子テーマ
  • PORIPU

どちらかのテーマのfunctions.phpにコピペするだけで実装可能です。

試してないので何とも言えませんが、対応するクラスやIDを適宜変更すれば、他テーマでも流用できると思います。

functions.phpには、必ずどちらか1つだけ書き込むようにしてください。
両方書き込まれているとブログ表示がぶっ壊れます!

1.途切れずなめらかに切り替わるバージョン

最初に公開したバージョン。
ラベルが途切れず、中身の文字だけ変化します。

functions.php
//上部固定の見出しラベルを作るよ
function kjk_fixed_headline_script() {
?>
<style>
    .kjk_fixed_headline {
    width: 100%;
    position: fixed;
    top: 0;
    padding-left: 10px;
    background-color: #899cff;
    color: #fff;
    font-size: 14px;
    font-weight: bold;
    z-index: 9999;
}
</style>
<script>
jQuery(function() {
  var posArray = new Array();
  var footer = 0;
  var count = 1;
  var block = '';
  posArray.length = 0;
  function fixed_headline() {
    jQuery('.entry-content h2,.entry-content h3,.entry-content h4,.entry-content h5,.entry-content h6').each(function(i){
      posArray[i] = jQuery(this).offset().top;
      block += '<span class="kjk_fixed_headline headline-' + count + '"><i class="fa fa-chevron-circle-right" aria-hidden="true"></i> ' + jQuery(this).text() + '</span>';
      count ++;
    });
    footer = jQuery('.article-footer').offset().top;
    jQuery('.footer').after('<div class="kjk_fixed_headline_block">' + block + '</div>');
    jQuery(window).scroll(headline_scroll).trigger('scroll');
  }
  function headline_scroll() {
    for (var i = posArray.length; i>=0; i--) {
      hidden();
      if (jQuery(window).scrollTop() < posArray[0] || jQuery(window).scrollTop() > footer) {
        break;
      } else if (jQuery(window).scrollTop() > posArray[i-1] + 0) {
        visible(i);
        break;
      }
    }
  }
  function visible(i) {
    jQuery('.kjk_fixed_headline_block .headline-' + i).css({'visibility': 'visible'});
  }
  function hidden() {
    jQuery('.kjk_fixed_headline_block span').css({'visibility': 'hidden'});
  }
  jQuery(window).load(function () {
    fixed_headline();
  });
});
</script>
<?php
}
add_action( 'wp', 'kjk_check_single' );
function kjk_check_single() {
  if ( is_single() ) {
    add_action('wp_footer', 'kjk_fixed_headline_script');
  }
}

2.ふわっと切り替わるバージョン

サルワカさんのように、ふわっと表示が切り替わります。

functions.php
//上部固定の見出しラベルを作るよ
function kjk_fixed_headline_script() {
?>
<style>
.kjk_fixed_headline {
width: 100%;
position: fixed;
top: 0;
padding-left: 10px;
background-color: #899cff;
color: #fff;
font-size: 14px;
font-weight: bold;
z-index: 50;
}
</style>
<script>
jQuery(function() {
  var posArray = new Array();
  var count = 1;
  var block = '';
  var flag = 0;
  var pos = 0;
  posArray.length = 0;
  function fixed_headline() {
    jQuery('.entry-content h2,.entry-content h3,.entry-content h4,.entry-content h5,.entry-content h6').each(function(i){
      posArray[i] = jQuery(this).offset().top;
      block += '<span class="kjk_fixed_headline headline-' + count + '"><i class="fa fa-chevron-circle-right" aria-hidden="true"></i> ' + jQuery(this).text() + '</span>';
      count ++;
    });
    posArray[posArray.length] = jQuery('.article-footer').offset().top;
    jQuery('.footer').after('<div class="kjk_fixed_headline_block">' + block + '</div>');
    jQuery(window).scroll(headline_scroll).trigger('scroll');
  }
  function headline_scroll() {
    pos = jQuery(window).scrollTop();
    if ( pos > posArray[flag-1] && pos < posArray[flag] ) {
      visible(flag);
    } else if ( pos < posArray[0] || pos < posArray[flag-1] || pos > posArray[flag] ) {
      hidden();
      for (var i = posArray.length; i>=0; i--) {
        if ( pos > posArray[posArray.length]) {
          flag = 0;
          break;
        } else if ( pos > posArray[i-1] ) {
          flag = i;
          break;
        }
      }
    }
  }
  function visible(i) {
    jQuery('.kjk_fixed_headline_block .headline-' + i).css({'visibility': 'visible'}).fadeIn('normal');
  }
  function hidden() {
    jQuery('.kjk_fixed_headline_block span').css({'visibility': 'hidden'}).fadeOut('fast');
  }
  jQuery(window).load(function () {
    fixed_headline();
  });
});
</script>
<?php
}
add_action( 'wp', 'kjk_check_single' );
function kjk_check_single() {
  if ( is_single() ) {
    add_action('wp_footer', 'kjk_fixed_headline_script');
  }
}

現在当ブログでは、こちらを利用しています。

全体のコードだけご紹介しましたが、カスタマイズの流れが知りたい方はここから少しだけお付き合いください。

カスタマイズ方法

カスタマイズ方法は大きく2通りあります。

  • FTPソフト等でファイルを編集してアップロードする
  • WordPressの管理画面上から直接編集する

どちらで行っても問題はありませんが、次の注意事項をよくご確認の上、安全に作業してください。

ご注意

こちらのカスタマイズは、テーマのfunctions.phpを編集します。

少しでも書き方を間違えるとブログの表示が真っ白になったり、壊れてしまう危険があります。

何かあった時に元に戻せるよう、作業前には必ずバックアップをとっておきましょう。

編集するファイルはfunctions.phpの1つだけです。

FTP経由の場合

FTPソフトでサーバーに接続し、ご利用中のテーマのフォルダ直下にあるfunctions.phpをダウンロードします。

ダウンロードできたらファイルを開き、適当な位置に冒頭のコードをまるごとコピペして保存しましょう。

保存できたらサーバーの元の位置にアップロードして終了です!

WordPressの管理画面から直接編集

管理画面から直接編集する場合は、管理メニューの[外観] -> [テーマの編集]を開きます。

右側のファイル一覧から[テーマのための関数(functions.php)]を選択して、画像にあるエリアのお好きな位置にコピペしましょう。

そのまま保存したら終了です!

コードの解説

それぞれの関数の動きについて、”なめらかに切り替わるバージョン”をモデルにちょっとだけ解説します。

まずはページが読み込まれて最初に実行される関数fixed_headlineの中身を見てみましょう。

fixed_headline
jQuery('.entry-content h2,.entry-content h3,.entry-content h4,.entry-content h5,.entry-content h6').each(function(i){
  posArray[i] = jQuery(this).offset().top;
  block += '<span class="kjk_fixed_headline headline-' + count + '"><i class="fa fa-chevron-circle-right" aria-hidden="true"></i> ' + jQuery(this).text() + '</span>';
  count ++;
});

この中では「entry-content」というクラスを持つh2からh6までのタグを一つずつ探し、それぞれの始まりの位置をposArrayという配列に格納していきます。

ついでにそれぞれの見出しタイトルを取得して、上部に固定するラベルの要素もblockという変数に追加しています。

fixed_headline
footer = jQuery('.article-footer').offset().top;

その後、同じように「article-footer」クラスの始点の位置を変数footerに格納。

article-footerは下部のフォローカードなどを表示している部分なので、ここまでスクロールしたら見出しラベルを非表示にする動作のためにこの処理が必要になります。

fixed_headline
jQuery('.footer').after('<div class="kjk_fixed_headline_block">' + block + '</div>');

ここで、さっき作っていたラベル要素をDOMにぶら下げます。

footerクラスの要素のあとに、after()を利用してねじ込ませるイメージですね。

この時点で全ての見出しラベルは画面上部に隠れているわけです。

fixed_headline
jQuery(window).scroll(headline_scroll).trigger('scroll');

ここまでで、見出しラベルを表示するための前準備はできあがっています。

最後にこちら。

画面がスクロールされた時にheadline_scroll関数を発火させるスクリプトです。

では、このheadline_scroll関数は何者なのか?
続いて見ていきましょう。

function headline_scroll() {
  for (var i = posArray.length; i>=0; i--) {
    hidden();
    if (jQuery(window).scrollTop() < posArray[0] || jQuery(window).scrollTop() > footer) {
      break;
    } else if (jQuery(window).scrollTop() > posArray[i-1] + 0) {
      visible(i);
      break;
    }
  }
}

ここでは、上部にガサッと量産した見出しラベルたちの表示/非表示の切り替えの処理を行っています。
このカスタマイズのキモのような関数ですねw

発火条件である「スクロール」が行われるたびに現在の位置と各見出しの位置をif文で比較して、その条件によってラベルを表示させたり消したり……。

よめねこ

くどい!

はるしか

切り替えてくれるんだよ(投げやり)

表示と非表示の部分で、また新しい関数が出てきました。

hidden()visible(i)ですね。

function visible(i) {
  jQuery('.kjk_fixed_headline_block .headline-' + i).css({"visibility": "visible"});
}
function hidden() {
  jQuery('.kjk_fixed_headline_block span').css({"visibility": "hidden"});
}

ここはぶっちゃけ切り分ける必要もなかったのですけど、自分でわかりやすくする為にあえて関数化しました。

やっていることは単純で、それぞれ「kjk_fixed_headline_blockクラスを持つ要素(ラベルのこと)のスタイルに、表示/非表示の値を付与する」だけ。

これらの関数が組み合わさって、スクロールされた時に今現在読んでいる章の見出しのラベルのみ表示する動作が実現しているのです。

さいごに

今回のカスタマイズは”ほぼ”すべてJavascriptでの処理になります。

phpはJavascripstを吐き出す為だけに動いているイメージですね。

なので、専用のjsファイルとcssファイルを作って読み込ませることでも再現できるカスタマイズです。

この記事では「誰でもコピペでできる」ことを重視して、functions.phpに記述するかたちでご紹介しました。

慣れている方なら数十秒で終わるような作業なので、ぜひお試しください!

6 COMMENTS

ぱいよん

はるしかさん初めまして。雑食ブログのカスタマイズ参考にさせていただいてます。知識のない自分には大助かりです。
此方の記事なのですが、書いてあるコードをコピペしてみたのですが何故か表示されませんでした。どのような原因が考えられますでしょうか?お手すきの時にでも一考いただければ幸いです。駄文失礼しました。

はるしか

ぱいよんさん、当ブログのカスタマイズ記事を参考にしていただき、ありがとうございます!

コードをコピペしても表示されないとのことですが、状況を知りえる手段がなく、あまり具体的なアドバイスができないかもしれません。

考えられる原因としては、キャッシュが残っている、jQueryが読み込まれていない、コピペが不完全、などがありますね。
一番農耕なのはキャッシュが残っている状態ですが、高速化のためにキャッシュ系プラグインなど利用されてませんでしょうか?
ご確認ください。
よろしくお願いします!

匿名

こんにちわ。
私も今 親と子テーマ(デモ版ではない方)を入れて、まっさらな状態でやりましたが表示されませんね。

テーマのための関数(functions.php)に間違いなく入れたし、入れる場所も間違っていません。
コピペミスもありません。

スーパーリロードしても変わりませんね…

どうしたものか。。

ches

こんにちは!こちら、実装できて大変助かっております。
文字を真ん中に表示する方法はありますでしょうか?
ご返信頂けたら幸いですm(_ _)m忙しい中素敵な記事をありがとうございます!

はるしか

chesさん、コメントありがとうございます。
当カスタマイズをご利用いただけて嬉しいです!
見出しのラベルを中央寄せにしたい場合、以下のコードを追加css、もしくはstyle.cssに追記いただければ実現可能かと思われます。

/* 見出しラベルの文字を中央寄せ */
.kjk_fixed_headline {
text-align: center;
}
/* END 見出しラベルの文字を中央寄せ */

お試しください!

現在コメントは受け付けておりません。