ポップアップと本文に目次を追加するカスタマイズ 結城永人 -2月 23, 2023 Imaginaryの記事/追加ページの本文の画面の左下に表示される概要ボタンは本文に見出し、HTMLのh1かh2かh3の見出しタグがあった場合にそれを取り込んだ目次を自動生成して表示します。 本稿ではボップアップの目次と本文への自動生成の目次の追加とポップアップのコンテンツのカスタマイズについて紹介します。 カスタマイズは全て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>time").textContent} / ${Blog1.querySelector("li.updated>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 => cpp.removeEventListener("click", scpp)); } summary_button.addEventListener("click", () => { wfsc.classList.toggle("hidden"); if (cpps[0]) cpps.forEach(cpp => 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 >= 最低数)に変更して下さい。 本文の見出しの数が最低数を含めて越えたときだけ目次が作られるようになります。 一部のページで目次表示を除外する方法 テンプレートにポップアップの目次を搭載すると全ての記事/追加ページに適用されます。 見出しがなければ目次は生成されませんが、見出しがあっても目次を生成したくないページがある場合、最初の見出しのHTMLの見出しタグに何かのclassを付けると共にポップアップの目次表示のソースコードのif (hdgs[0])の部分をif (hdgs[0] && !hdgs[0].classList.contains("見出しに付けたclass")に変更します。 見出しのh2にno-tocのclassを付けて除外するならば 編集部分①投稿の編集画面のHTMLビュー <h2 class="no-toc">見出し</h2> 編集部分②テンプレートの最後のscript。 if (hdgs[0] && !hdgs[0].classList.contains("no-toc")) {...} ※太字が新しく追加する部分。 テンプレートは一回だけ、投稿は目次を作りたくないページがあるときに編集します。 それぞれのclassは半角の英数字とハイフン(-)やアンダーバー(_)などのclassで使用可能な一部の記号に置き換えても構いませんが、ポップアップの目次表示を除外するためには必ず一致させて下さい。 見出しの数を制限したソースコードの場合はhdgs[0]の代わりのhdgs.length >= 最低数に同じように&& !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で指定されている内容は次の通りです。 .smctmax-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)>summarylist-style-type:none目次の左横のマーカー(▼)を消します。details:has(.mdr) olpadding-$startSide:1.25em目次の項目の左の内側の余白を調整します。details:has(.mdr) limargin:4px auto個々の項目の外側の余白を調節します。.mdrmargin-bottom:0目次の下の外側の余白を消します。 初期のCSSの内容を変えたり、新しいCSSを追加したりしてポップアップの目次のデザインをカスタマイズできます。 参考サイトCSSはどう使えば良いのか|タグ自体とidとclassの指定先とstyleタグとインラインの記述法 本文にも目次を表示する方法 テンプレートのソースコードの二箇所を編集します。 最後の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 => cpp.removeEventListener("click", scpp)); } summary_button.addEventListener("click", () => { wfsc.classList.toggle("hidden"); if (cpps[0]) cpps.forEach(cpp => 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) => { 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; }); 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>detailsbackground-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>summarydisplay:flex本文の目次の見出しの置き方を整えます。justify-content:space-between}本文の目次のタイトルと開閉ボタンを左右に分けます。#toc spantext-decoration:dotted underline .125em本文の目次の開閉ボタンに点線の下線を引きます。#toc>details>summary>span::beforecontent:'開く'本文の目次が閉じたときに「開く」と表示します。#toc>details[open]>summary>span::beforecontent:'閉じる'本文の目次が開いたときに「閉じる」と表示します。 追加したCSSの内容を変えたり、新しいCSSを追加したりしてポップアップの目次のデザインをカスタマイズできます。 参考サイトCSSはどう使えば良いのか|タグ自体とidとclassの指定先とstyleタグとインラインの記述法 ポップアップのコンテンツのカスタマイズ ポップアップの目次以外のコンテンツの扱いについて載せます。 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/三番目ポップアップの記事/付いページのURLp/四番目ポップアップの記事/付いページの公開日と更新日p/五番目ポップアップの記事/付いページの著者名とブログ名 最初は画像と五つの文章の集まりが表示されます。 ポップアップのコンテンツの削除について 画像を消したい場合は画像のb:tagを削除します。 文章の集まりを消したい場合は五つのpタグを含めた文章の親ボックスのdivタグと最後のscriptタグの/* 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}-`); 文章はdivタグだけ削除してscriptタグのソースコードを残しておくとエラーで、概要ボタンが動作しなくなります。 ポップアップのコンテンツの置き替えについて 画像と文章の親ボックスはそれぞれのタグで置き替え可能です。 個々の文章は四番目と五番目以外はpタグだけで置き換え可能です。 四番目の公開日と更新日の文章を動かしたい場合はpタグに何かのclassを付けて先程の削除用のscriptタグのpau = aab.previousElementSiblingをpau = wfsc.querySelector("p.クラス名")に書き換えて下さい。 五番目の著者名とブログ名の文章を動かしたい場合は四番目の文章の動かすカスタマイズを行った上で――四番目の文章を動かさなくてもプログラムで関連しているために必要です――さらに同じようにpタグに何かのclassを付けて先程の削除用のscriptタグのaab = wfsc.querySelector("div.smtx").lastElementChildをaab = 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で記載して載せられますが、その場合でもセレクターを個別に指定すれば目次をコンテンツの間に挿入することができます。 コメント 新しい投稿 前の投稿
ブログの背景のヘッダー画像の付け方とサイズについて Bloggerでの背景のヘッダー画像の付け方 Imaginaryの背景のヘッダー画像はBloggerの管理画面のテーマのカスタマイズ(テーマデザイナー)の背景の背景画像の「背景を変更」からBloggerの既存のものを選択するか使用中のデバイスに保存してあるものをアップロードし...
フォント変更のためのVariableタグの一覧表 Bloggerブログのフォント(字体)はカスタマイズで変更することができます。 Bloggerブログでフォントを変更する方法 管理画面のテーマのカスタマイズのテーマデザイナーのフォントで用意された一部の英数字以外はCSSを書き換える必要があり、その場合、Imaginary...
投稿の日付表示を日本語の順番に変える方法 Imaginaryの記事ページでは記事タイトルの下に投稿の公開日、本文の下に更新日が表示されます。 日付をどのように表示するかというフォーマット(形式)はBloggerの管理画面のタイムスタンプの形式で変えることができます、 設定| Blogger 公開日と更新日の両...
アドセンスの自動広告に対応済み Bloggerはサイト広告の アドセンス を管理画面の「収益」から設定して――ライセンスがなければブログを申請して審査に合格したかぎり――「レイアウト」のウィジェットから選択して直ぐに使える。 テンプレートは公式テーマならば間違いなくそうだし、Imaginaryも同じようにア...
皆のImaginaryへの気持ちはどうなのか Blank wall with dark band above grey pavement by Maarten Deckers on Unsplash Imaginaryについて意見や感想が載せられた記事を紹介する。 テーマをずっと気になっていた「Imaginary」...
読み込みボタン/無限スクロールの手動化のカスタマイズ Imaginaryのインデックスページ、つまりトップページとアーカイブページとラベルページとブログ内の検索結果ページではスクロールが画面下に達すると次のページを自動的に読む込むという無限スクロールが搭載されています。 本稿では画面スクロールによる動作を停止して読み込みボタンで...
パンくずリストの構造化データにラベルを追加する Imagimaryの記事/追加ページにはパンくずリストの構造化データが付いています。 構造化データは検索エンジンからのアクセスを想定してサイト作成を行うSEO(Search Engine Optimization/検索エンジン最適化)対策の一環で、パンくずリストは一つのページ...
インデックスページのスニペットの本文の削除と項目の並び替えのカスタマイズ Imaginaryのインデックスページ:トップとアーカイブとラベルとブログ内検索では記事のスニペットが表示されますが、初期値では記事のタイトルと画像と抜粋と二つのリンク(アーカイブと続きを読む)が表示されます。 テンプレートのデザインのカスタマイズとしてスニペットの本文の削除...
記事/追加ページの画像の遅延読み込みや軽量化による高速化のカスタマイズ ブログに画像や動画を掲載すると容量が大きくてページの表示速度が下がります。閲覧するのに時間が訪問者を減るかも知れないので、なるべくページの表示速度を高めた方が良いと思います。 初回画面が三秒以内に表示されれば遅くて嫌になることは少ないといわれます。 魅力的な画像や動画を掲...
コメント