ホーム
サービス
ノーコード相談サービスShopifyを用いたEC制作飲食店特化のWEB制作
ブログ一覧会社概要お問い合わせ
公開日 
2020-12-04
更新日 
2020-12-03

Webflowで作成したブログページに自動生成される目次を追加する方法

目次

WebflowのCMS機能を用いて作成したサイトのブログで、目次を自動生成する方法について解説していきます。
この手順に沿って行えば、ブログの見出しタグから自動で目次が生成されるようになります。目次を追加することで、UXが高まるので、是非追加してみましょう。

今回は、こちらのページに目次を追加することを想定して作成していきます。

※最後にコピペするだけのコードを記載しておりますので、理解していくのがめんどくさいという方は最後のコードをお使いください。

表示エリアの設置とSelectorの設定

目次を表示するエリアを作成し、ブログの本文のエリアに対してSelectorを設置していきます。

目次エリアの追加とSelectorの設定

CMS Collection PagesにあるBlog Posts Templateで、ブログタイトルの下に目次のエリアを追加する必要があります。
今回は、目次のエリアとしてDiv Block(Selectorは「Post Outline」とします)を追加し、その子要素として「目次」というテキストと、自動生成される目次を表示するエリアになるDiv Block(Selectorは「toc」とします)を追加します。

ブログのコンテンツにSelectorを設定

ブログのコンテンツから目次を自動生成するために、コンテンツのエリアのSelectorに「Post Content」を追加します。

この段階でのWebflowで表示はこのようになっているはずです。

Javascriptのコード追加

‍
ブログ本文の見出しタグから目次を自動生成するために、Javascriptのコードを追加していきます。
弊社ではブログのタイトルにh1タグをつけ、見出しにはh2、h3タグをつけるというルールで本文の作成を行なっているため、
h2・h3タグから目次を自動生成するというルールで行なっていきます。
h4タグも使っているという方は、h4タグに関するコードを追記いただければ、h4タグも含めた自動生成を行うことが出来ます。

ここでは、コードをBlog Post Templateのページの「Before tag」に追加していきます。
「Before tag」に追加する手順は下記になります。

目次を自動生成するコードの追加

下記のコードを追加し、ブログ本文から目次が自動生成されるようにします。
今回はブログ本文のエリアに「Post Content」というSelectorを設定しており、ブログページが表示される際には、このエリアのclass名はpost-contentとなります。
本文のエリアに設定するSelectorに応じて、追加するスクリプト内にある'containar'の箇所は変更してください。

<script>
!function(a){a.fn.smoothScroller=function(b){b=a.extend({},a.fn.smoothScroller.defaults,b);var c=a(this);return a(b.scrollEl).animate({scrollTop:c.offset().top-a(b.scrollEl).offset().top-b.offset},b.speed,b.ease,function(){var a=c.attr("id");a.length&&(history.pushState?history.pushState(null,null,"#"+a):document.location.hash=a),c.trigger("smoothScrollerComplete")}),this},a.fn.smoothScroller.defaults={speed:400,ease:"swing",scrollEl:"body,html",offset:0},a("body").on("click","[data-smoothscroller]",function(b){b.preventDefault();var c=a(this).attr("href");0===c.indexOf("#")&&a(c).smoothScroller()})}(jQuery),function(a){var b={};a.fn.toc=function(b){var c,d=this,e=a.extend({},jQuery.fn.toc.defaults,b),f=a(e.container),g=a(e.selectors,f),h=[],i=e.activeClass,j=function(b,c){if(e.smoothScrolling&&"function"==typeof e.smoothScrolling){b.preventDefault();var f=a(b.target).attr("href");e.smoothScrolling(f,e,c)}a("li",d).removeClass(i),a(b.target).parent().addClass(i)},k=function(){c&&clearTimeout(c),c=setTimeout(function(){for(var b,c=a(window).scrollTop(),f=Number.MAX_VALUE,g=0,j=0,k=h.length;k>j;j++){var l=Math.abs(h[j]-c);f>l&&(g=j,f=l)}a("li",d).removeClass(i),b=a("li:eq("+g+")",d).addClass(i),e.onHighlight(b)},50)};return e.highlightOnScroll&&(a(window).bind("scroll",k),k()),this.each(function(){var b=a(this),c=a(e.listType);g.each(function(d,f){var g=a(f);h.push(g.offset().top-e.highlightOffset);var i=e.anchorName(d,f,e.prefix);if(f.id!==i){a("<span/>").attr("id",i).insertBefore(g)}var l=a("<a/>").text(e.headerText(d,f,g)).attr("href","#"+i).bind("click",function(c){a(window).unbind("scroll",k),j(c,function(){a(window).bind("scroll",k)}),b.trigger("selected",a(this).attr("href"))}),m=a("<li/>").addClass(e.itemClass(d,f,g,e.prefix)).append(l);c.append(m)}),b.html(c)})},jQuery.fn.toc.defaults={container:"body",listType:"<ul/>",selectors:"h1,h2,h3",smoothScrolling:function(b,c,d){a(b).smoothScroller({offset:c.scrollToOffset}).on("smoothScrollerComplete",function(){d()})},scrollToOffset:0,prefix:"toc",activeClass:"toc-active",onHighlight:function(){},highlightOnScroll:!0,highlightOffset:100,anchorName:function(c,d,e){if(d.id.length)return d.id;var f=a(d).text().replace(/[^a-z0-9]/gi," ").replace(/\s+/g,"-").toLowerCase();if(b[f]){for(var g=2;b[f+g];)g++;f=f+"-"+g}return b[f]=!0,e+"-"+f},headerText:function(a,b,c){return c.text()},itemClass:function(a,b,c,d){return d+"-"+c[0].tagName.toLowerCase()}}}(jQuery);

$('.toc').toc({
    'selectors': 'H2,H3', 
    'container': '.post-content', 
    'prefix': 'toc',
    'highlightOnScroll': true,
    'highlightOffset': 100,
 });
</script>

コード追加後の目次エリアの表示はこのようになります。

各見出しにidを付与

この状態でも目次内の項目をクリックした際に該当する見出しまでスクロールがされますが、正しく動かないケースがあります。

これは、各見出しに付与されているidが見出しのタイトルに依存しているためです。
例えば見出しにアルファベットが含まれない場合は、同じidが付与されるといった事象が発生するため、正しくスクロールが行われません。
今回は、下記のコードを追加し、見出し順にidを1,2,3・・と付与していきます。

<script>
// H2,H3のタグ箇所を取得し、それぞれにid付与
const sections = document.querySelectorAll(".post-content > H2,H3");
for (var i = 0; i < sections.length; i++) {
    sections[i].id=(i+1);
}
</script>

これで、目次クリック時に正しくスクロールが行われます。

目次エリアの表示非表示

ブログページに寄って、見出しが存在しないケースもあるかもしれません。
今回は、ブログ本文にh2タグの見出しがない場合には、目次エリアを非表示にします。
目次エリアには「Post Outline」というSelectorを設定しており、下記コードを追加することで、表示非表示の切り替えを行うことが出来ます。

<script>
const sectionsH2 = document.querySelectorAll(".post-content > H2");
if (sectionsH2.length == 0){
	document.getElementById("post-outline").style.display = "none";
}
</script>

cssのコード追加

今の状態では、h2の見出しもh3の見出しも並列で表示されており見にくいので、見た目の改善を行います。

目次にナンバリングを行うためにコードを追加

ナンバリングを行うために、下記のコードを追加してください。

<style>
body{
	counter-reset:h2number h3number; 
}
li.toc-h2{
	counter-reset:h3number; 	
}
li.toc-h2:before{
	counter-increment:h2number; 
	content:counter(h2number) ". ";
}
.toc-h3:before{
	counter-increment:h3number; 
	content:counter(h2number) "-"counter(h3number)". ";
}
</style>

コード追加後の目次エリアの表示はこのようになります。

見た目を整えるためのコードを追加

リストのマークは非表示にし、またh3タグの見出しに対応する箇所は、左側にmarginを作ることで、少し右にずらします。
下記のコードを追加してください。

<style>
.toc-h3{
  margin-left: 24px; 
}
.toc li {
    list-style: none;
}
</style>

コード追加後の目次エリアの表示はこのようになり、これで完了です。

コピペするだけのコード

ここまで長々と解説してきましたが、最後にここまで解説してきた全コードを載せておきます。
これをコピペするだけで、目次の自動生成を実装することができます。

<style>
.toc-h3{
  margin-left: 24px; 
}
.toc li {
    list-style: none;
}

body{
	counter-reset:h2number h3number; 
}
li.toc-h2{
	counter-reset:h3number; 	
}
li.toc-h2:before{
	counter-increment:h2number; 
	content:counter(h2number) ". ";
}
.toc-h3:before{
	counter-increment:h3number; 
	content:counter(h2number) "-"counter(h3number)". ";
}
</style>

<script>
// H2,H3のタグ箇所を取得し、それぞれにid付与
const sections = document.querySelectorAll(".post-content > H2,H3");
const sectionsH2 = document.querySelectorAll(".post-content > H2");
for (var i = 0; i < sections.length; i++) {
    sections[i].id=(i+1);
}
if (sectionsH2.length == 0){
	document.getElementById("post-outline").style.display = "none";
}

!function(a){a.fn.smoothScroller=function(b){b=a.extend({},a.fn.smoothScroller.defaults,b);var c=a(this);return a(b.scrollEl).animate({scrollTop:c.offset().top-a(b.scrollEl).offset().top-b.offset},b.speed,b.ease,function(){var a=c.attr("id");a.length&&(history.pushState?history.pushState(null,null,"#"+a):document.location.hash=a),c.trigger("smoothScrollerComplete")}),this},a.fn.smoothScroller.defaults={speed:400,ease:"swing",scrollEl:"body,html",offset:0},a("body").on("click","[data-smoothscroller]",function(b){b.preventDefault();var c=a(this).attr("href");0===c.indexOf("#")&&a(c).smoothScroller()})}(jQuery),function(a){var b={};a.fn.toc=function(b){var c,d=this,e=a.extend({},jQuery.fn.toc.defaults,b),f=a(e.container),g=a(e.selectors,f),h=[],i=e.activeClass,j=function(b,c){if(e.smoothScrolling&&"function"==typeof e.smoothScrolling){b.preventDefault();var f=a(b.target).attr("href");e.smoothScrolling(f,e,c)}a("li",d).removeClass(i),a(b.target).parent().addClass(i)},k=function(){c&&clearTimeout(c),c=setTimeout(function(){for(var b,c=a(window).scrollTop(),f=Number.MAX_VALUE,g=0,j=0,k=h.length;k>j;j++){var l=Math.abs(h[j]-c);f>l&&(g=j,f=l)}a("li",d).removeClass(i),b=a("li:eq("+g+")",d).addClass(i),e.onHighlight(b)},50)};return e.highlightOnScroll&&(a(window).bind("scroll",k),k()),this.each(function(){var b=a(this),c=a(e.listType);g.each(function(d,f){var g=a(f);h.push(g.offset().top-e.highlightOffset);var i=e.anchorName(d,f,e.prefix);if(f.id!==i){a("<span/>").attr("id",i).insertBefore(g)}var l=a("<a/>").text(e.headerText(d,f,g)).attr("href","#"+i).bind("click",function(c){a(window).unbind("scroll",k),j(c,function(){a(window).bind("scroll",k)}),b.trigger("selected",a(this).attr("href"))}),m=a("<li/>").addClass(e.itemClass(d,f,g,e.prefix)).append(l);c.append(m)}),b.html(c)})},jQuery.fn.toc.defaults={container:"body",listType:"<ul/>",selectors:"h1,h2,h3",smoothScrolling:function(b,c,d){a(b).smoothScroller({offset:c.scrollToOffset}).on("smoothScrollerComplete",function(){d()})},scrollToOffset:0,prefix:"toc",activeClass:"toc-active",onHighlight:function(){},highlightOnScroll:!0,highlightOffset:100,anchorName:function(c,d,e){if(d.id.length)return d.id;var f=a(d).text().replace(/[^a-z0-9]/gi," ").replace(/\s+/g,"-").toLowerCase();if(b[f]){for(var g=2;b[f+g];)g++;f=f+"-"+g}return b[f]=!0,e+"-"+f},headerText:function(a,b,c){return c.text()},itemClass:function(a,b,c,d){return d+"-"+c[0].tagName.toLowerCase()}}}(jQuery);

$('.toc').toc({
    'selectors': 'H2,H3', 
    'container': '.post-content', 
    'prefix': 'toc',
    'highlightOnScroll': true,
    'highlightOffset': 100,
 });
</script>

お疲れ様でした!!

‍

Tweet
Tagged:
ローコード
阿部 紘凡
取締役
全てのブログを見る
人気記事
Shopify
ECサイトを今すぐShopifyに移行すべき3つの理由
Tags
SNS
カゴ落ち
シェアボタン
レスポンシブ
ローコード
外部連携
移行
新着記事を受け取る
ありがとうございます。登録が完了いたしました。
登録に失敗しました。メールアドレスを確認し、再度お試しください。
Follow Us
Subscribe

新着記事を受け取る

ご登録ありがとうございます!
登録に失敗しました。
More Posts

オススメの投稿

Shopify
Shopifyのカゴ落ちを減らす方法を具体的に解説
2020-12-23
 by 
室伏 正裕
Shopify
ECサイトを今すぐShopifyに移行すべき3つの理由
2020-11-27
 by 
室伏 正裕
Webflow
WebflowのCMS機能を用いて作成したブログページにTwitterシェアボタンを追加する方法
2020-11-27
 by 
阿部 紘凡
Studio
STUDIOのフォームをGoogleスプレッドシートと連携する手順
2020-11-24
 by 
阿部 紘凡

我々は、お客様の成功をもってして
我々の提供物の価値が示されると信じています。

ホーム
ブログ一覧お問い合わせ
ブログ
ShopifyBubble
サービス
ノーコード相談サービスShopifyを用いたEC制作飲食店特化のWEB制作
© 2020 QED inc.