スキップしてメイン コンテンツに移動

Imaginary theme

ポップアップと本文に目次を追加するカスタマイズ

Imaginaryの記事/追加ページの本文の画面の左下に表示される概要ボタンは本文に見出し、HTMLのh1かh2かh3の見出しタグがあった場合にそれを取り込んだ目次を自動生成して表示します。

本稿ではボップアップの目次と本文への自動生成の目次の追加とポップアップのコンテンツのカスタマイズについて紹介します。

Imaginaryの自動生成の目次が記事の本文とポップアップに表示されている

カスタマイズは全てBloggerの管理画面の「テーマ」のカスタマイズの右横のメニューボタン(▼)のHTMLを編集かバックアップと元に戻すからテンプレートのソースコードを書き換えます。

追記:Imaginaryのポップアップの目次は2023年4月3日のバージョンから搭載していますので、それ以前のバージョンを使っている場合はポップアップの目次を表示できるバージョンに取り替えて下さい。

ポップアップの目次のソースコードについて説明します。

最後のscriptタグのSummary buttonのソースコード

ポップアップの目次を自動生成して表示するためのものです。

/* Summary button */
const pb = Blog1.querySelector("div.entry-content"), hdgs = pb.querySelectorAll("h1, h2, h3");
if (hdgs[0]) {
const dts = document.createElement("details"), smr = document.createElement("summary"), fid = document.createElement("ol");
dts.open = true; smr.insertAdjacentHTML("afterbegin", "見出し"); fid.className = "mdr"; dts.appendChild(smr); dts.appendChild(fid);
let n;
hdgs.forEach((hdg, i) => {
const tci = document.createElement("li"), tcl = document.createElement("a"), tn = Number(hdg.tagName.substring(1));
if (!hdg.id) hdg.id = `content_${i + 1}`; tcl.href = `#${hdg.id}`; tcl.textContent = hdg.textContent; tci.appendChild(tcl);
if (i !== 0 && tn > 1) {
const lid = [...fid.querySelectorAll("li")].pop(), dr = tn - n;
if (dr > 0) {
const idx = document.createElement("ol");
idx.appendChild(tci); lid.appendChild(idx); } else if (dr === 0) {
lid.after(tci); } else {
lid.closest("ol").parentElement.after(tci); }} else {
fid.appendChild(tci); }
n = tn; });
const ift = summary_button.firstElementChild;
wfsc.firstElementChild.insertAdjacentElement("afterbegin", dts); ift.classList.add("original-icon"); ift.setAttribute("viewBox", "0 0 24 24"); ift.innerHTML = "<path d='M2 4 H22 M7.3 9.4 H22 M7.3 14.7 H22 M7.3 20 H22'/><circle cx='3.5' cy='9.4' r='0.5'/><circle cx='3.5' cy='14.7' r='0.5'/><circle cx='3.5' cy='20' r='0.5'/>"; }
const aab = wfsc.querySelector("div.smtx").lastElementChild, pau = aab.previousElementSibling;
pau.textContent = `${Blog1.querySelector("a.published&gt;time").textContent} / ${Blog1.querySelector("li.updated&gt;time").textContent}`;
if (Blog1.querySelector(".fn")) aab.insertAdjacentHTML("afterbegin", `${Blog1.querySelector(".fn").textContent} - `);
const cpps = wfsc.querySelectorAll("ol.mdr a");
function scpp() {
wfsc.classList.add("hidden"); cpps.forEach(cpp =&gt; cpp.removeEventListener("click", scpp)); }
summary_button.addEventListener("click", () =&gt; {
wfsc.classList.toggle("hidden");
if (cpps[0]) cpps.forEach(cpp =&gt; cpp.addEventListener("click", scpp)); });

ポップアップの目次は本文の見出しタグのh1とh2とh3を取り込んで自動生成されています。

表題として「見出し」と表示されます。変更したい場合はソースコードの前の方の「見出し」を他の言葉に書き換えて下さい。

目次の項目から見出しのジャンプリンクを付けるために本文の見出しタグのidを取り出してidが付いてないもの(通常の投稿では何も付きません)は新しく付けています。

新しく付けられる見出しタグのidはcontent_見出しの順番となります。

文字列のcontent_の部分は他の半角の英数字とハイフン(-)やアンダーバー(_)などのidで使用可能な一部の記号に置き換えても構いません。

見出しのidを全てcontent_見出しの順番と同じ仕方で纏めたい場合はソースコードのif (!hdg.id) hdg.id = `content_${i + 1}`;if (!hdg.id)を削除すると見出しの元のidを上書きすることができます。

そして("h1, h2, h3")は取り込む見出しタグの種類で、減らしても動作に支障はありません。

Bloggerの作成ビューの見出しタグ

主見出し
h1
見出し
h2
小見出し
h3
準見出し
h4

Imaginaryの記事/追加ページではページタイトルに見出しのh1タグが付いてますので、本文では見出しのh2から使うとHTMLの全体の構成が良いと思います。

目次に取り込む見出しタグを減らす場合は区切りの半角コンマ(,)を残さないように注意して下さい。残すとプログラムのエラーで、概要ボタンが動作しなくなります。

h1を消した場合、ソースコードのif (i !== 0 && tn > 1)の一部は不要ですので、消してif (i !== 0)だけでも構いません。

取り込む見出しタグの種類を増やすこともできます。

h4を追加する場合、ソースコードの取り込む見出しタグの種類のところに「h4」を追加した上で、次のソースコードを変更して下さい。

元のソースコード

lid.closest("ol").parentElement.after(tci);

新しいソースコード

const pol = lcs.parentElement;
if (dr === -1) {
pol.after(tci); } else {
pol.closest("ol").parentElement.after(tci);
if (tci.parentElement.tagName !== "OL") fid.appendChild(tci); }

同じソースコードによって投稿のHTMLビューでh5やh6の見出しタグを使った場合、取り込む見出しタグの種類のところに「h5」や「h6」を追加するとポップアップの目次に取り込むこともできます。

少ない見出しで目次を作る必要がない場合は目次を作り始める見出しの最低数を設定できます。

ソースコードの最初の方の(hdgs[0])(hdgs.length &gt;= 最低数)に変更して下さい。

本文の見出しの数が最低数を含めて越えたときだけ目次が作られるようになります。

一部のページで目次表示を除外する方法

テンプレートにポップアップの目次を搭載すると全ての記事/追加ページに適用されます。

見出しがなければ目次は生成されませんが、見出しがあっても目次を生成したくないページがある場合、最初の見出しのHTMLの見出しタグに何かのclassを付けると共にポップアップの目次表示のソースコードif (hdgs[0])の部分をif (hdgs[0] &amp;&amp; !hdgs[0].classList.contains("見出しに付けたclass")に変更します。

見出しのh2にno-tocのclassを付けて除外するならば

編集部分①投稿の編集画面のHTMLビュー

<h2 class="no-toc">見出し</h2>

編集部分②テンプレートの最後のscript。

if (hdgs[0] &amp;&amp; !hdgs[0].classList.contains("no-toc")) {...}

※太字が新しく追加する部分。

テンプレートは一回だけ、投稿は目次を作りたくないページがあるときに編集します。

それぞれのclassは半角の英数字とハイフン(-)やアンダーバー(_)などのclassで使用可能な一部の記号に置き換えても構いませんが、ポップアップの目次表示を除外するためには必ず一致させて下さい。

見出しの数を制限したソースコードの場合はhdgs[0]の代わりのhdgs.length &gt;= 最低数に同じように&amp;&amp; !hdgs[0].classList.contains("見出しに付けたclass")を追加します。

ページの種類、記事ページか追加ページで目次の有無を切り替えるならばポップアップの目次表示のソースコードの一部をBloggerの振り分けタグで囲って下さい。

<b:if cond='data:view.isページの種類>
const pb = Blog1.querySelector("div.post-body"), hdgs = pb.querySelectorAll("h1, h2, h3");
(中略)
summary_button.firstElementChild.innerHTML = ""; }
</b:if>
(中略)

※太字が新しく追加する部分。

ソースコードの帯文字の「ページの種類」にポップアップの目次表示を行いたいページを入力します。

記事ページ
Post
追加ページ
Page

当の振り分けタグに入力されなかったページで、ポップアップの目次表示が除外されます。

前半のCSSのフローティングボタン/メッセージのソースコード

ポップアップの目次のデザインを付けるためのものです。

テンプレートの前半のskn内のソースコードがデザインのCSSになっています。

ポップアップの目次のCSSは「フローティングボタン/メッセージ」というコメントのところに纏められています。CSSに同じコメントのところが、複数、ありますが、最初のもので、「SVGアイコン」の次に置かれたソースコードです。

.smct {display:grid;grid-template-columns:repeat(auto-fit, minmax(calc($(content.width / 3) - (var(--floatingbar-height) + var(--fixedbutton-margin) + var(--maincolumn-padding)) * 2), 1fr));gap:1em;font-size:small;padding:var(--maincolumn-padding);background-color:$(body.background.color);color:$(body.text.base.color);border:1px $(sidebar.separator.color) double;box-shadow:5px 5px 10px -5px rgba(0, 0, 0, .4);margin:0;height:min(80dvh - (var(--floatingbar-height) + var(--fixedbutton-margin)) * 3, 480px - (var(--floatingbar-height) + var(--fixedbutton-margin)) * 2);overflow-y:scroll}
details:has(.mdr)>summary {list-style-type:none}
details:has(.mdr) ol {padding-$startSide:1.25em}
details:has(.mdr) li {margin:4px auto}
.mdr {margin-bottom:0}

CSSで指定されている内容は次の通りです。

.smct
  • max-height:min(80dvh - (var(--floatingbar-height) + var(--fixedbutton-margin)) * 3, 480px - (var(--floatingbar-height) + var(--fixedbutton-margin)) * 2)
    スマホでポップアップのコンテンツが増えて縦長になっても画面内に十分に収まるようにして最大でも画像の元の横幅(480px)から上下の隙間を引いたところまでに抑えます。
  • overflow-y:scroll
    スマホでポップアップのコンテンツが増えて縦長になって途切れた部分をスクロールで見えるようにします。
details:has(.mdr)>summary
  • list-style-type:none
    目次の左横のマーカー(▼)を消します。
details:has(.mdr) ol
  • padding-$startSide:1.25em
    目次の項目の左の内側の余白を調整します。
details:has(.mdr) li
  • margin:4px auto
    個々の項目の外側の余白を調節します。
.mdr
  • margin-bottom:0
    目次の下の外側の余白を消します。

初期のCSSの内容を変えたり、新しいCSSを追加したりしてポップアップの目次のデザインをカスタマイズできます。

参考サイト

本文にも目次を表示する方法

テンプレートのソースコードの二箇所を編集します。

最後のscriptタグのSummary buttonを編集する

元のソースコード

/* Summary button */
const pb = Blog1.querySelector("div.entry-content"), hdgs = pb.querySelectorAll("h1, h2, h3, h4");
(中略)
cpp.addEventListener("click", scpp)); });

途中を省略しているので、実際のソースコードはもっと長いです。

本文と共用のポップアップの目次表示のソースコード

新しいソースコード

/* Summary button */
const aab = wfsc.querySelector("div.smtx").lastElementChild, pau = aab.previousElementSibling;
pau.textContent = `${Blog1.querySelector("a.published>time").textContent}/${Blog1.querySelector("li.updated>time").textContent}`;
if (Blog1.querySelector(".fn")) aab.insertAdjacentHTML("afterbegin", `${Blog1.querySelector(".fn").textContent}-`);
if (Blog1.querySelector("nav#toc")) {
wfsc.firstElementChild.insertAdjacentElement("afterbegin", toc.firstElementChild.cloneNode(true)); summary_button.firstElementChild.classList.add("original-icon"); summary_button.firstElementChild.innerHTML = "<path d='M2 4 H22 M7.3 9.4 H22 M7.3 14.7 H22 M7.3 20 H22'/><circle cx='3.5' cy='9.4' r='0.5'/><circle cx='3.5' cy='14.7' r='0.5'/><circle cx='3.5' cy='20' r='0.5'/>"; }
const cpps = wfsc.querySelectorAll("ol.mdr a");
function scpp() {
wfsc.classList.add("hidden"); cpps.forEach(cpp =&gt; cpp.removeEventListener("click", scpp)); }
summary_button.addEventListener("click", () =&gt; {
wfsc.classList.toggle("hidden");
if (cpps[0]) cpps.forEach(cpp =&gt; cpp.addEventListener("click", scpp)); });

元のソースコードを新しいソースコードで置き換えて下さい。

script内の一番最後の「</b:if>});」を消さないようにして下さい。消すと他のボタンなどの全ての機能が止まります。

Blog1のwidgetタグのpostBodyのidのincludableを編集する

<b:includable id='postBody' var='post'>
  <!-- If metaDescription is empty, use the post body as the schema.org description too, for G+/FB snippeting. -->
    <div class='post-body entry-content' expr:id='"post-body-" + data:post.id'>
      <data:post.body/>
    </div>
  本文の目次表示のソースコード
</b:includable>

本文の目次表示のソースコード

<b:if cond='data:view.isSingleItem'><script>
const pb = Blog1.querySelector("div.entry-content"), hdgs = pb.querySelectorAll("h1, h2, h3");
if (hdgs[0]) {
const toc = document.createElement("nav"), dts = document.createElement("details"), smr = document.createElement("summary"), fid = document.createElement("ol");
toc.id = "toc"; dts.open = true; smr.insertAdjacentHTML("afterbegin", "目次<span/>"); fid.className = "mdr"; dts.appendChild(smr); dts.appendChild(fid); toc.appendChild(dts);
let n;
hdgs.forEach((hdg, i) =&gt; {
const tci = document.createElement("li"), tcl = document.createElement("a"), tn = Number(hdg.tagName.substring(1));
if (!hdg.id) hdg.id = `content_${i + 1}`; tcl.href = `#${hdg.id}`; tcl.textContent = hdg.textContent; tci.appendChild(tcl);
if (i !== 0 &amp;&amp; tn &gt; 1) {
const lid = [...fid.querySelectorAll("li")].pop(), dr = tn - n;
if (dr &gt; 0) {
const idx = document.createElement("ol");
idx.appendChild(tci); lid.appendChild(idx); } else if (dr === 0) {
lid.after(tci); } else {
lid.closest("ol").parentElement.after(tci); }} else {
fid.appendChild(tci); }
n = tn; });
hdgs[0].before(toc); }</script></b:if>

二つのソースコードを、それぞれ、所定のscriptタグ所定のincludableタグに追加すると概要ボタンのポップアップの先頭と本文の最初の見出しの直前に目次が表示されるようになり、概要ボタンのアイコンが目次用のものに切り替わります。

本文の目次は単体で使うことができます。その場合、ポップアップの目次のカスタマイズは不要です。

一部のページで目次表示を除外する方法

一部のページで目次表示を除外したい場合、ページを個々に除外する方法はポップアップだけの場合のカスタマイズと全く同じです。

ページの種類で目次表示の有無を切り替える場合は本文の目次表示のソースコードにBloggerの記事/追記ページの振り分けタグの<b:if cond='data:view.isSingleItem'></b:if>が最初から付いてますので、さらにもう一つの振り分けタグで新しく囲わずに「SingleItem」の部分を目次表示を行いたいページの種類の「Post」(記事ページ)か「Page」(追加ページ)に書き換えて、そのまま、使って下さい。

本文の目次は最初の見出しの直前に表示されます。

目次の内容やその他のカスタマイズについては概要ボタンから目次を表示するに載せたものと変わりません。

前半のskinタグのフローティングボタン/メッセージを編集する

同じメッセージが、複数、ありますが、最初のもので、「SVGアイコン」の次に置かれたソースコードです。

ポップアップの目次のCSSに続けて次のCSSを追加して下さい。

#toc>details {background-color:rgba($(sidebar.separator.color.red), $(sidebar.separator.color.green), $(sidebar.separator.color.blue), 0.02);border:1px $(sidebar.separator.color) outset;padding:1em}
#toc>details>summary {display:flex;justify-content:space-between}
#toc span {text-decoration:dotted underline .125em}
#toc>details>summary>span::before {content:'開く'}
#toc>details[open]>summary>span::before {content:'閉じる'}

CSSで指定されている内容は次の通りです。

#toc>details
  • background-color:rgba($(sidebar.separator.color.red), $(sidebar.separator.color.green), $(sidebar.separator.color.blue), 0.02)
    本文の目次の背景色を付けます。
  • border:1px $(sidebar.separator.color) outset
    本文の目次の枠線を付けます。
  • padding:1em
    本文の目次の内側の余白を付けます。
#toc>details>summary
  • display:flex
    本文の目次の見出しの置き方を整えます。
  • justify-content:space-between}
    本文の目次のタイトルと開閉ボタンを左右に分けます。
#toc span
  • text-decoration:dotted underline .125em
    本文の目次の開閉ボタンに点線の下線を引きます。
#toc>details>summary>span::before
  • content:'開く'
    本文の目次が閉じたときに「開く」と表示します。
#toc>details[open]>summary>span::before
  • content:'閉じる'
    本文の目次が開いたときに「閉じる」と表示します。

追加したCSSの内容を変えたり、新しいCSSを追加したりしてポップアップの目次のデザインをカスタマイズできます。

参考サイト

ポップアップの目次以外のコンテンツの扱いについて載せます。

attributionのidのsectionタグの直前を編集する

<button class='svg-icon-24-button hidden' expr:aria-label='data:messages.learnMore' id='summary_button' type='button'>
<svg class='svg-icon-24' role='img'><use href='/responsive/sprite_v1_6.css.svg#ic_more_vert_black_24dp'/></svg>
</button>
<div class='hidden' id='wfsc'>
<figure class='smct'>
<b:tag cond='data:view.featuredImage' expr:alt='data:messages.photo' expr:height='252' expr:src='resizeImage(data:view.featuredImage, 480, "1200:630")' loading='lazy' name='img' width='480'/>
<div class='smtx'>
<p><data:view.title.escaped/></p>
<p><data:blog.metaDescription.escaped/></p>
<p><data:view.url.canonical/></p>
<p/>
<p><data:blog.title.escaped/></p>
</div>
</figure>
</div>

このソースコードが概要ボタンとポップアップのコンテンツのソースコードです。

button id='summary_button'
概要ボタン
div id='wfsc'
ポップアップの大外の配置枠
figure class='smct'
ポップアップの親ボックス
b:tag name='img'
ポップアップの画像
div class='smtx'
ポップアップの文章の親ボックス
p/一番目
ポップアップの記事/付いページのタイトル
p/二番目
ポップアップの記事/付いページの検索向け説明
p/三番目
ポップアップの記事/付いページのURL
p/四番目
ポップアップの記事/付いページの公開日と更新日
p/五番目
ポップアップの記事/付いページの著者名とブログ名

最初は画像と五つの文章の集まりが表示されます。

ポップアップのコンテンツの削除について

画像を消したい場合は画像のb:tagを削除します。

文章の集まりを消したい場合は五つのpタグを含めた文章の親ボックスのdivタグと最後のscriptタグの/* Summary button */のところから次のソースコードを削除します。

const aab = wfsc.querySelector("div.smtx").lastElementChild, pau = aab.previousElementSibling;
pau.textContent = `${Blog1.querySelector("a.published&gt;time").textContent}/${Blog1.querySelector("li.updated&gt;time").textContent}`;
if (Blog1.querySelector(".fn")) aab.insertAdjacentHTML("afterbegin", `${Blog1.querySelector(".fn").textContent}-`);

文章はdivタグだけ削除してscriptタグのソースコードを残しておくとエラーで、概要ボタンが動作しなくなります。

ポップアップのコンテンツの置き替えについて

画像と文章の親ボックスはそれぞれのタグで置き替え可能です。

個々の文章は四番目と五番目以外はpタグだけで置き換え可能です。

四番目の公開日と更新日の文章を動かしたい場合はpタグに何かのclassを付けて先程の削除用のscriptタグのpau = aab.previousElementSiblingpau = wfsc.querySelector("p.クラス名")に書き換えて下さい。

五番目の著者名とブログ名の文章を動かしたい場合は四番目の文章の動かすカスタマイズを行った上で――四番目の文章を動かさなくてもプログラムで関連しているために必要です――さらに同じようにpタグに何かのclassを付けて先程の削除用のscriptタグのaab = wfsc.querySelector("div.smtx").lastElementChildaab = wfsc.querySelector("p.クラス名")に書き換えて下さい。

目次はポップアップの先頭に表示されますが、画像や文章の集まりと置き換えたい場合は最後のscriptタグに新しく追加するソースコードを編集して下さい。

ポップアップの最後に目次を表示する

ポップアップだけの目次表示の場合

wfsc.firstElementChild.insertAdjacentElement("beforeend",dts);

ポップアップと本文の目次表示の場合

wfsc.firstElementChild.insertAdjacentElement("beforeend", toc.firstElementChild.cloneNode(true));

※太字が変更する部分。

どちらも元の「afterbegin」がポップアップの先頭の指定で、「beforeend」がポップアップの末尾の指定です。

ポップアップの何れかのコンテンツの次に目次を表示する

ポップアップだけの目次表示の場合

wfsc.querySelector("セレクター").insertAdjacentElement("afterend",dts);

ポップアップと本文の目次表示の場合

wfsc.querySelector("セレクター").insertAdjacentElement("afterend", toc.firstElementChild.cloneNode(true));

※太字が変更する部分。

どちらも元のソースコードの「firstElementChild」と「afterbegin」と書き換えます。

セレクターは置き換える目次の直前に来るものについて入力します。

CSSと同じ書き方で、大丈夫で、ポップアップの画像ならば一つしかないので、「img」、文章の親ボックスならば「div.smct」となります。

ポップアップの親ボックス、文章の親ボックスには色んなコンテンツをHTMLで記載して載せられますが、その場合でもセレクターを個別に指定すれば目次をコンテンツの間に挿入することができます。

  • ブログの投稿者: 結城永人
  • タイトル: ポップアップと本文に目次を追加するカスタマイズ
  • 最終更新: 
自分の写真
二十代前半から作家活動を天職として何よりも励んで来ました。当初は小説家を志望していましたが、十年を経て作詩する機会も増すほどに詩人こそ素性だと認めるに至りました。以降、個人的に永遠を歌う生き方として自分の中で最も重要な位置を占めています。ブログについては2015年から『些細な日常』を本格的に運営しています。人生健康芸術学問娯楽開発言語政治社会歴史生物自然、等々、どんな話題でも自由気儘に取り上げるつもりです。今までの経験を活かしながら新しい思考や表現を得られれば良いと思ってやっています|学歴:経済学士。職歴:物流業。資格:はんだ付け。特技:ダイエット。

コメント

注目の投稿

日付: 

ImaginaryのBloggerブログへの付け替え方

イメージ

人気の投稿

読み込みボタン/無限スクロールの手動化のカスタマイズ

イメージ

Imaginaryのインデックスページ、つまりトップページとアーカイブページとラベルページとブログ内の検索結果ページではスクロールが画面下に達すると次のページを自動的に読む込むという無限スクロールが搭載されています。 本稿では画面スクロールによる動作を停止して読み込みボタンで...

記事/追加ページの画像の遅延読み込みや軽量化による高速化のカスタマイズ

イメージ

ブログに画像や動画を掲載すると容量が大きくてページの表示速度が下がります。閲覧するのに時間が訪問者を減るかも知れないので、なるべくページの表示速度を高めた方が良いと思います。 初回画面が三秒以内に表示されれば遅くて嫌になることは少ないといわれます。 魅力的な画像や動画を掲...

インデックスページのスニペットの本文の削除と項目の並び替えのカスタマイズ

イメージ

Imaginaryのインデックスページ:トップとアーカイブとラベルとブログ内検索では記事のスニペットが表示されますが、初期値では記事のタイトルと画像と抜粋と二つのリンク(アーカイブと続きを読む)が表示されます。 テンプレートのデザインのカスタマイズとしてスニペットの本文の削除...