2015/03/31

HTML内のコード色付き表示highlight.jsのBloggerへの設置とカスタマイズ

HTML文書内にプログラムなどを貼り付ける際には、多くのプログラム記述向けエディタのような色付き表示がされていると見やすいが、JavaScriptとCSSを用いて自動的に色付け処理を行う “Syntax Highlighter” と呼ばれる類のプログラムの内、 “highlight.js” というものをBloggerの本ウェブログで用いることにした。

ここではその設置と外観のカスタマイズに関するメモを扱う。

  1. コードの取得
  2. 設置
    1. テンプレートへの埋め込みによる設置
      1. JavaScriptコード
      2. CSSコード
    2. Google ドライブを用いた設置
    3. CDNを使用する場合
  3. 記事内の記述について
  4. 外観テーマのカスタマイズ
    1. 外観テーマ内の色指定対象に関する表現
    2. カスタマイズの要領

コードの取得

ダウンロードページのカスタムパッケージの機能を用いて必要最小限の言語サポートの圧縮されたコードを取得しておく。

使用しない言語のチェックは全て外してファイルサイズを可能な限り減らしておく。

設置

テンプレートへの埋め込みによる設置

ここではBloggerのテンプレートへスクリプト本体を埋め込む形での利用についてを扱う。

JavaScriptコード

Bloggerのテンプレートでは基本的にはCDATAセクションを用いてJavaScriptのスクリプトを貼り付けるのだが、HTML/XMLの言語サポート[1]が含まれていると “</script>” の部分がスクリプトの終了部分とみなされて正常に動作しない。これを防ぐために、 “同文字列を分断してからつなげる” という方法をとることにする。

あらかじめ元のソースから文字列を検索し、適当なところで文字列を切って “+” で結合する。

[挿入]Bloggerのテンプレート内、body要素の終了タグのすぐ上あたり
<script type='text/javascript'>
// <![CDATA[
!function(e){"undefined"!=typeof ...

...

... starts:{e:"</scr"+"ipt>",rE:!0,sL:"javascript"} ...

... });
hljs.initHighlightingOnLoad ();
// ]]>
</script>

CSSコード

highlight.jsには標準で多くの外観テーマ[2]が存在し、その中から好きなものを選んで “CSSコード” という形で使うことができる。

使用したい外観テーマもしくはそれをカスタマイズしたCSSコードの全体をBloggerの “テンプレート - カスタマイズ - 上級者向け - CSS を追加” の入力欄か、もしくは “テンプレート - HTML の編集” でテンプレートのコード内のCSSコードの記述部分に追加して保存(更新)する。

Google ドライブを用いた設置

スクリプトを外部ファイル化すると内容がキャッシュされるので、データ転送量が抑えられるなどのメリットがある。ここではGoogle ドライブを用いた設置についてを扱う。

まずは準備として

  1. スクリプトを事前にGoogle ドライブへアップロード
  2. 共有の詳細設定でアクセス権限を “ウェブ上で一般公開” に指定

とした上で、共有リンクとして得られるURLに含まれる長い文字列部分を用いてBloggerのテンプレートへ

[挿入]Bloggerのテンプレート内、body要素の終了タグのすぐ上あたり
<script src='https://googledrive.com/host/0B7lD3ipVFmhjUURnLW9uMTg2UDA' type='text/javascript'/>

のように[3]記述を追加すると、Google ドライブへ配置したスクリプトが参照できる。CSSコードについても同様にURLを得てテンプレートに記述を追加することで外部に設置できる。[4]

下は指定したURLの外部CSSファイルをJavaScriptで追加読み込みする例(link要素を使用)。

[挿入]Bloggerのテンプレート内、body要素の終了タグのすぐ上あたり
<script>
// <![CDATA[
function loadHighlightCss ()
{
  var elem = document.createElement ("link");
  elem.setAttribute ("href", "https://googledrive.com/host/...");  // 実際のURLを入れる必要がある
  elem.setAttribute ("rel", "stylesheet");
  elem.setAttribute ("type", "text/css");
  document.getElementsByTagName ("head")[0].appendChild (elem);
}
loadHighlightCss ();
// ]]>
</script>

highlight.jsのCSSコードはそれほど大きくはないため、JavaScriptのスクリプトにCSSファイルの内容を含めて読み込ませる方法(style要素を使用)もある。

[挿入]Google ドライブへアップロードするJavaScriptファイルの先頭など
function loadHighlightCss ()
{
  var elem = document.createElement ("style");
  elem.setAttribute ("type", "text/css");
  elem.innerHTML = " ... ";  // CSSファイルの内容を貼り付ける
  document.getElementsByTagName ("head")[0].appendChild (elem);
}
loadHighlightCss ();

この方法ではスクリプトのファイルへの参照を追加するだけで設置できる。[5]下は上記のスクリプトとhighlight.jsのスクリプトをまとめた、(本記事公開時点で)本ウェブログで使用しているものを参照するための記述。

[挿入]Bloggerのテンプレート内、body要素の終了タグのすぐ上あたり
<script src='https://googledrive.com/host/0B7lD3ipVFmhjamhWUEt5UElPazg' type='text/javascript'/>

CDNを使用する場合

ダウンロードページにCDNからの参照用のコードがあるのでこれをテンプレートに挿入するのが最も手っ取り早いのだが、追加の言語サポートは利用できず、また、外観テーマをカスタマイズしたい場合はテンプレートに記述(Google ドライブへの参照含む)を追加する必要が出てくる。

記事内の記述について

Bloggerの記事編集ではHTMLモードで直接HTMLコード(ソース)を編集する必要があるが、それ以外には記事内の記述に関する注意点はなく、highlight.jsの通常の使い方(言語名を示すクラス名のあるcode要素をpre要素の中に含める)で記述すれば動作する。

Pythonのコードを記述する例
<pre><code class="py">from __future__ import print_function
print ('Pythoooooon !!')</code></pre>

言語名とクラス名の対応はソースをダウンロード・展開してdocs/css-classes-reference.rstを開くことでも確認できる(先頭の名前が正式名で2つ目からはエイリアスとなる)。

外観テーマのカスタマイズ

  • テーマによっては一部の言語で色が適切に付かない
  • 大部分の見栄えは好みでも一部の色だけが気に入らない

など、カスタマイズして使いたい場合にこの調整作業をいちいちBlogger側の設定をいじりながら行うのは大変なので、以下の手順で公式ページにあるデモページの各言語のコードを使いながら調整することにした。

  1. Webブラウザからデモページを開き “Language categories” を “all” にした後でページを保存[6]
  2. テキストエディタでHTMLファイルを新規に作成
  3. “ベースにしたいスタイルシートファイル[7]の内容” + “カスタマイズしたい言語のソース部分” の形になるように(保存したHTMLファイルとCSSファイルからコピペして)編集し、Webブラウザで開く
  4. テキストエディタでCSSコードを編集しながらWebブラウザ側で更新を行い、これを納得がいく出来になるまで繰り返す
テスト用HTMLファイルの例
<style type="text/css">

/* ここにベースのCSSファイルの内容を貼り付ける */

</style>

<div id="languages">

  <div style="display: block;" class="...">
    <h2>言語名1</h2>
    <pre><code class="lang1 hljs">...</code></pre>
  </div>

  <div style="display: block;" class="...">
    <h2>言語名2</h2>
    <pre><code class="lang2 hljs">...</code></pre>
  </div>

  ...

  <div style="display: block;" class="...">
    <h2>言語名n</h2>
    <pre><code class="langn hljs">...</code></pre>
  </div>

</div>

外観テーマ内の色指定対象に関する表現

highlight.jsの色付き表示のHTMLコードは、言語名を示すクラス[8]code要素の中に “hljs-[文字列]” 形式のクラスのspan要素群が含まれる形となっており

  • 言語名を示す文字列
  • 色付け対象の部分を示す文字列

の組み合わせを用いて色指定対象を細かく指定することができる。上記それぞれの実際の文字列は、保存済みのHTMLファイルの該当言語部分のソースや既存の外観テーマのCSSファイルを参照することで確認できる[9]

下は実際のスタイル定義の一部。形としてはこのように指定言語/場面の羅列(セレクタ部分)に対して色指定などを記述するものとなる。

[引用]ファイル名:atelier-heath.light.css
/* Atelier Heath Light Blue */
.hljs-function,
.python .hljs-decorator,
.python .hljs-title,
.ruby .hljs-function .hljs-title,
.ruby .hljs-title .hljs-keyword,
.perl .hljs-sub,
.javascript .hljs-title,
.coffeescript .hljs-title {
  color: #516aec;
}

カスタマイズの要領

既存の定義済みの色を用いる場合はセレクタ部分に “.[言語を示すクラス名] .[対象部分を示すクラス名],” の形の記述を追加したり削除や置換をしたりしてカスタマイズする。

  • ベースとする外観テーマの中に該当する記述がない[10]場合は新しくセレクタ部分に追加
  • 既に該当言語に関するセレクタの記述がある場合は、それを消して[11]必要であれば新しいものに書き換える
  • Webブラウザで表示を確認しながら調整し、調整が済んだら先述の設置の要領で変更を反映
カスタマイズ後の記述例
.hljs-function,
.diff .hljs-deletion,
.ini .hljs-string, .ini .hljs-number, .ini .hljs-keyword, .ini .hljs-value,
.markdown .hljs-link_url, .markdown .hljs-link_reference,
.python .hljs-decorator,
.python .hljs-title,
.ruby .hljs-function .hljs-title,
.ruby .hljs-title .hljs-keyword,
.perl .hljs-sub,
.xml .hljs-pi,
.xml .hljs-doctype,
.javascript .hljs-title,
.coffeescript .hljs-title {
  color: #516aec;
}

もちろん、既存のファイルで使用されていない色を新しく使うように記述を追加することもできるが、同じような形のCSSコードの追加になるため、例は紹介しない。

[1]: 圧縮されていないソースではxml.jsというファイル
[2]: このプログラムでは “スタイル” と呼んでいる
[3]: “https://googledrive.com/host/” の後ろに文字列を付ける形でsrc属性を指定する
[4]: 外部ファイル化は場合によってはページ表示速度に影響するため、外部ファイルの数は可能な限り減らした上で、特にCSSファイルの場合は外部ファイルに記述する指定対象を “スクロールしないと見えない場所のもの” などに限定させる
[5]: HTTPのリクエスト数が減らせる上にテンプレートへの追加コードも短くできるため、個人的にはこちらの形が好み
[6]: 保存形式が選択できる場合は “完全” な形を選択して、関連ファイル群を含めて保存する
[7]: ファイル名は外観テーマの名前から大体分かる
[8]: エイリアス不可・内部でエイリアスから処理される正式な名前
[9]: 言語名のクラスについては先述のリファレンス内の言語ごとの先頭の名前としても確認可
[10]: 元々色が付いていないか、外側の要素の色になっている
[11]: 近くにコメントの形で置いても可