当サイトはトップページに記事を表示していませんので問題ないのですが、別グログの「そんなにも褒めないよ。映画評」では、トップページに最新の1記事とその下に最新記事一覧を表示しています。
その際、記事の途中に「続きを読む」を挿入しています。
で、この「続きを読む」は、記事タイトルと同様に記事ページへのリンクになっていますので、当然、ページのトップへ飛んでしまいます。それを「続きを読む」の位置へ飛ばそうと思います。
(2017/10/30)記事中の Javascript に変数宣言がもれている箇所がありました
01はてなブログ「続きを読む」の仕様
はてなブログの「続きを読む」がどうなっているかを見てみますと、
- ツールバーの「続きを読む」アイコンをクリックすると
<!-- more -->
が挿入される - トップページでは、
<a class="entry-see-more" href="記事URL">続きを読む</a>
に変換される - 記事ページでは削除される
となっています。
記事ページに <!-- more -->
が残っていれば、ページを開いた時にそこまで飛べばいいのですが、痕跡がなければどうしようもありません。
02「続きを読む」クリックで記事ページ「続き」位置に飛ばす仕様
で、どうするかといいますと、
- トップページなら
- 記事本文だけを配列に入れ
- 各記事内で「続きを読む」を探し、あれば
- 「続きを読む」のリンクにクエリパラメータ
readmore=本文の子要素の数
を追加する
としておけば、「続きを読む」をクリックした時だけ、「続きを読む」までの記事本文の子要素数、たとえば、「続きを読む」が10個目の子要素であれば、 ?readmore=10
などのクエリパラメータを持った URL で呼ばれます。
次に、記事ページですが、
- URL にクエリパラメータがあれば
- パラメーターを配列に入れ
- 各要素に対して、キーが
readmore
なら - 本文の
パラメータの値
番目の子要素までページをスクロールする
これでいけるはずです。
03「続き」位置までスクロールする Javascript
/** * 即時関数 */ (function(){ // トップページなら if (document.body.classList.contains('page-index')) { // 記事の数だけ繰り返す Array.prototype.forEach.call(document.getElementsByClassName('entry-content'), function(elem){ var seeMore = elem.getElementsByClassName('entry-see-more'); // 「続きを読む」があれば if (seeMore.length !== 0) { // リンクにクエリパラメータを追加する seeMore[0].href = seeMore[0].href + '?readmore=' + elem.childElementCount; } }); } }()); /** * 読み込みが完了したら実行 * 他に onload があれば上書きしてしまうので注意 */ window.onload = function(){ // クエリパラメータを取得 var query = location.search.substring(1); // クエリパラメータがあれば if (query) { // 今回はパラメータはひとつなので必要ないが念のため var params = query.split('&'); for (i = 0; i < params.length; i++) { var item = params[i].split('='); // パラメータキーが readmore なら if (item[0] === 'readmore') { // 「続きを読む」のひとつ前の要素を取得しクラス readmore を付加する var elem = document.getElementsByClassName('entry-content')[0].children[item[1]-1]; elem.classList.add('readmore'); // 「続きを読む」のひとつ前の要素の絶対座標までスクロールさせる smoothScroll(elem.getBoundingClientRect().top); } } } }; /** * 指定要素までスクロールする関数 * @param {number} targetY (要素の絶対y座標) * パラメータを 0 とすればページトップまで飛ぶ */ function smoothScroll(targetY) { var startY = window.pageYOffset; var f = ( targetY > startY ) ? true : false; // 'down' = true : 'up' = false setTimeout(function(){ if( f && (startY <= targetY)){ startY = startY + (targetY - startY) / 20 + 1; window.scrollTo(0, startY); setTimeout(arguments.callee, 10); } else if ( !f && startY >= targetY){ startY = startY - (startY - targetY) / 20 - 1; window.scrollTo(0, startY); setTimeout(arguments.callee, 10); }else{ window.scrollTo(0, targetY); } }, 10); }
window.onload
の部分は、他にクエリパラメータがないことが分かっていますので、もっと簡潔に
window.onload = function(){ var query = location.search.substring(1); if (query) { var item = query.split('='); var elem = document.getElementsByClassName('entry-content')[0].children[item[1]-1]; elem.classList.add('readmore'); smoothScroll(elem.getBoundingClientRect().top); } };
でもいけます。また、スクロール後の位置を調整する場合は、
smoothScroll(elem.getBoundingClientRect().top - 100);
とすれば、「続き」位置の上部に 100px の余裕が出来ます。
また、スクロールが鬱陶しかったり、ぎこぎこする場合は、
// smoothScroll(elem.getBoundingClientRect().top); window.scrollTo(0, elem.getBoundingClientRect().top);
として、直接飛ばしてしまえばいいです。
さらに、読み込み完了を待たずに移動したい場合は、window.onload
内のコードをすべて即時関数の中に入れてしまえば、読み込み完了を待たずに移動するはずです。
04「続き」の読み始めをわかりやすく装飾する
「続き」の読み始めにクラス名 readmore
を付加してありますので、CSS で「続き」の読み始め位置をわかりやすくすることが出来ます。
サンプルCSS
p.readmore::before { content: '\f006'; font-family: 'blogicon'; color: red; margin-right: 1rem; text-shadow: 0.5rem 0 0 red; }
rem
は、em
や px
など、使用している単位に変更してください。