はてなブログでソースコードにタイトルを付ける

はてなブログに載せたプログラムのソースコードにタイトルとか付けたい時ってありますよね。 Hugo とかの静的サイト・ジェネレータでテンプレートとか SCSS とか載せたいけど、コードを書いたファイルの置き場所は仕様で決まっているので、そのファイルのパスも明示してコードファイル名をキャプションにしたい。そういう需要はけっこうあります。

検索するといろんな方がいろんな方法でやっていて、中には JavaScript まで使っている方も居たりとか。私も Jekyll や Hugo の記事に使うのにフィルターやらショートコードやら自作してやっていたんですが、そういうの連発すると、もとの Markdown の可読性が低くなって読みづらいです。ソースコードにタイトルを付ける程度のことに、JavaScript 使ってサイトを重くしたりしたくないし、何か簡易な方法は無いものかと。

CSSだけで工夫する簡単な方法

で、最近 Hugo の記事を書くのに使っている単純なやり方を、多少生成されるHTMLが違う はてなブログ用にCSSを調整して使ってみました。 以下がその表示。

oldUnload.js

var oldUnload = window.onbeforeunload;
window.onbeforeunload = function() {
    saveCoverage();
    if (oldUnload) {
        return oldUnload.apply(this, arguments);
    }
};

HTMLの直書きで可読性が多少下がるのは妥協します。ソースコードの上にちょこっとタイトル用のPタグを追加するだけ。後はCSSで形を作ってます。実際の Markdown 内に書いた形がこれ。

 <p class="caption tab">oldUnload.js</p>

 ```javascript
 var oldUnload = window.onbeforeunload;
 window.onbeforeunload = function() {
     saveCoverage();
     if (oldUnload) {
         return oldUnload.apply(this, arguments);
     }
 };
 ```

Hugo だと シンタックスハイライトの記法の上を1行空けないとおかしくなります。はてなブログではこの空行は不要のようですが、一応他とあわせるために空行を入れています。DIVタグなどで囲んで工夫してる方もおられますが、囲まない方法をとりました。はてなブログでは囲んでも問題なさそうですが、他で同じ Markdownの記事を流用しようとすると、いろいろややこしい問題が起きます。空行を入れるのもそういう関係です。おそらく Markdown パーサによって違うんだと思います。シンタックスハイライト記法のソースコードは、素直に Markdown パーサに渡るようにしておくのが無難だと思われます。

数式ブロックにもタイトルを

じゃあ、これを使って数式ブロックにもタイトルを付けられるようにしてみましょう。 前から設定してる数式ブロックの表示がこれ。

$$ \sin(α+β)=\sinα\cosβ+\cosα\sinβ $$

sampleというクラスを付けて細い枠付きにしてるバージョン。

$$ \sin(α+β)=\sinα\cosβ+\cosα\sinβ $$

このsampleクラス付きの数式ブロックをベースに、タイトルを付けます。

加法定理

$$ \sin(α+β)=\sinα\cosβ+\cosα\sinβ $$

Markdown中の書き方はこれ。

<p class="caption tab">加法定理</p>
<div class="math display sample">
$$
\sin(α+β)=\sinα\cosβ+\cosα\sinβ
$$
</div>

枠の色をタイトルのタブと揃えたもの。

加法定理

$$ \sin(α+β)=\sinα\cosβ+\cosα\sinβ $$

書き方はこれ。

<p class="caption tab">加法定理</p>
<div class="math display sample withCaption">
$$
\sin(α+β)=\sinα\cosβ+\cosα\sinβ
$$
</div>

もっと簡易なタイプ

コードブロックにタイトル付けるぐらいで、枠とかいらない、無理にタブ型とかにしなくていいというのもありだと思います。でもソースコードの前にPタグやDIVタグでタイトル付けても、もともと本文用などでmarginpaddingline-heightの値があって、それらが優先するためにコードに関連したタイトルらしい位置に落ち着かないのですよね。なんだか少し離れた上のほうに来る。

【 oldUnload.js 】<== こんなところにタイトルが!

var oldUnload = window.onbeforeunload;
window.onbeforeunload = function() {
    saveCoverage();
    if (oldUnload) {
        return oldUnload.apply(this, arguments);
    }
};

なので、色付き文字だけの簡易バージョンも作ってみました。

【 oldUnload.js 】

var oldUnload = window.onbeforeunload;
window.onbeforeunload = function() {
    saveCoverage();
    if (oldUnload) {
        return oldUnload.apply(this, arguments);
    }
};

書き方はタブ型のクラス名.tab.rawに変えるだけ。

<p class="caption raw">【 oldUnload.js 】</p>

数式ブロックにも使える。

【加法定理】

$$ \sin(α+β)=\sinα\cosβ+\cosα\sinβ $$

ただし数式の場合も、数式ブロックとタイトルの間に1行空行が無いとタイトルが埋もれてしまった。おそらくはてなブログの場合は Hugo と違い空行が無くてもシンタックスが崩れないので、もし1行空けないで使うなら、CSSmargin-bottomを見直さないといけない。でもそれすると、コードブロック用と数式ブロック用のCSSを別にしないといけなくなるのでやめておきます。

CSS

これらのスタイルを定義してるCSSです。これをカスタムCSSに追加しただけ。

タブ型キャプションを使いたければ.caption.tabを付ければいい。簡易版なら.caption.raw。基底クラスの.captionは文字の色とサイズ等だけ共通にするもの。はてなブログのベースCSSはけっこうしっかり目なので、どうしても!important多めです。

/ Code with caption /
.caption {
  font-size: 0.9rem;
  font-weight: normal;
  font-style: normal;
  color: #602020 !important;
}
.caption.raw {
  margin: 40px 0 -22px !important;
  padding: 0 0.5rem !important;
  line-height: 0 !important;
  height: 1.0rem;
}
.caption.tab {
  position: relative;
  top: -23px;
  left: 1px;
  box-sizing: border-box;
  width: fit-content;
  height: 32px;
  margin-top: 3.5rem !important;
  margin-left: 0 !important;
  margin-bottom: -30px !important;
  z-index: 90;
  padding: 2px 6px;
  background-color: #f5f5dc;
  border: solid 1px #f5f5dc;
  border-radius: 3px 3px 0 0;
}
.caption.tab + pre.code {
  position: relative;
  box-sizing: border-box;
  z-index: 100;
  border: solid 3px #f5f5dc;
}
/ Math sample /
.math.display {
  position: relative;
  width: auto;
  margin: 30px 15px 40px;
  padding: 15px;
  z-index: 100;
  color: #333333;
  box-sizing: border-box;
  background: #ffffff;
}
.math.display.sample {
  border: 1px solid #cccccc;
}
.caption.tab + .math.display.sample.withCaption {
  border: solid 3px #f5f5dc;
}
.math.display.sample.line {
  padding: 2.0rem;
}

こんな程度でコードにタイトルを付けてみました。Chromeでの表示は問題なし。私のスマホは Pixel 4 ですが、今んとこ問題なく表示されてます。他の機種は知らんけどw