Gatsbyの記事管理にMarkdownを使っているときに、コードブロックの見栄えにシンタックスハイライトを適用する方法です。
見せ方によっては別途CSS調整が必要にはなるものの、基本的には必要プラグインを読み込むだけでシンタックスハイライトを適用させることが可能です。
紹介している内容はGatsby Ver 3.9.1を使用して動作確認したものになります。
また、使用するプラグインはいずれも「gatsby-transformer-remark」のサブプラグインとなります。
シンタックスハイライトを適用
シンタックスハイライトを適用には「gatsby-remark-prismjs」と「PrismJS」のプラグインが必要になるのでインストールします。
$ npm i gatsby-remark-prismjs prismjs
gatsby-config.js
には「gatsby-transformer-remark」のサブプラグインとして指定し、オプション指定なしの場合は下記のように記述します。
plugins: [
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [
`gatsby-remark-prismjs`,
],
},
},
],
次にCSSでの見栄え調整で、「PrismJS 」ではあらかじめいくつかのテーマが用意されているので、それらに対応するCSSを読み込むだけで見栄えを整えることができます。
テーマはDefault・Dark・Funky・Okaidia・Twilight・Coy・Solarized Light・Tomorrow Nightの8種類で、例えばデフォルトテーマを適用させたい場合はgatsby-browser.js
に下記のように記述して読み込ませます。
import 'prismjs/themes/prism.css'
他のテーマを読み込みたい場合はprism.css
の部分を任意で変更し、デフォルトテーマ以外の読み込みはそれぞれ下記になります。
- Dark →
import 'prismjs/themes/prism-dark.css'
- Funky →
import 'prismjs/themes/prism-funky.css'
- Okaidia →
import 'prismjs/themes/prism-okaidia.css'
- Twilight →
import 'prismjs/themes/prism-twilight.css'
- Coy →
import 'prismjs/themes/prism-coy.css'
- Solarized Light →
import 'prismjs/themes/prism-solarizedlight.css'
- Tomorrow Night →
import 'prismjs/themes/prism-tomorrow.css'
あとは、Markdown記事に該当コード前後をバッククォート3つで括る形でコードブロックを記述し、開始バッククォート後には対応言語を指定します。
例えば、JavaScriptのコードを表示するには下記のように記述し、その他の対応言語についてはPrismJSのSupported languagesで確認できます。
```js
const numbers = [1, 2, 3, 4, 5];
const customNumbers = numbers.map(num => {
return num * 2;
});
console.log(customNumbers);
```
記述後、該当の記事ページを確認するとイメージのようにシンタックスハイライトが適用されているのを確認できます。
見栄えを自分好みに調整
シンタックスハイライトの見栄えを自分好みにしたい場合は、下記セレクタを用いてスタイル指定したものをグローバルCSSなどに記述すれば可能です。
サンプルコードはprism.css
のスタイル指定になります。
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
font-size: 1em;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
code[class*="language-"]::selection, code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.token.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
/* This background color was intended by the author of this theme. */
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
オプション設定
オプションではコードを括るpre
要素やcode
要素へのclass指定(classPrefix
)、エイリアス指定(aliases
)、行番号表示(showLineNumbers
)などを指定できます。
plugins: [
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [
{
resolve: `gatsby-remark-prismjs`,
options: {
classPrefix: `language-`,
inlineCodeMarker: null,
aliases: {},
showLineNumbers: false,
noInlineHighlight: false,
},
},
],
},
},
],
行番号表示のオプションについては、showLineNumbers: true
にするのに加えてgatsby-browser.js
でimport 'prismjs/plugins/line-numbers/prism-line-numbers.css'
を読み込む必要があり、場合によってはコード表示部分と位置がずれている可能性があるので、それは別途各自で調整する必要があります。
また、showLineNumbers: true
にした場合すべてのコードブロックが対象となるので、一部のコードブロックでのみ有効化したい場合はgatsby-browser.js
でfalse
にしておき、下記のようにコードブロック記述時の言語指定後にその旨を記述します。
```js{numberLines: true}
... 省略
```
ちなみに、行番号を特定の番号から開始させたい場合は、同じく各コードブロック記述時に指定します。
例えば、開始番号を3からにしたい場合は下記のように記述します。
```js{numberLines: 3}
... 省略
```
特定行をハイライト表示する
コードブロック内の特定行をハイライト表示(目立たせたい)場合は、下記のように記述することでその行が.gatsby-highlight-code-line
というclass付きのspan
要素で括られるので、あとはそれにdisplay; block
を指定したり背景色を設定するなどのスタイル調整を行うことで実装できます。
```js{1}
... 省略
```
このサンプルコードは1行目のみをハイライト指定する場合ですが、例えば1行目と3行目をハイライトにしたい場合は,
区切りで{1,3}
のように記述すれば複数指定でき、1〜5行目などまとめてハイライト指定したい場合は-
を用いて{1-5}
のように記述すれば複数行をまとめて指定することができます。
タイトルを表示
コードブロック上にタイトルを表示させたい場合は「gatsby-remark-code-titles」を利用します。
$ npm i gatsby-remark-code-titles
オプション指定など不要な場合は、「gatsby-remark-prismjs」と同様にgatsby-config.js
に「gatsby-transformer-remark」のサブプラグインとして指定し、その際「gatsby-remark-prismjs」より前に記述します。
plugins: [
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [
`gatsby-remark-code-titles`,
`gatsby-remark-prismjs`,
],
},
},
],
あとは、Markdown記事のコードブロックで対応言語に続けて:title=ここにタイトル
のように記述すればタイトルが表示されるのを確認でき、例えば下記のように記述すれば「example.js」というタイトルがコードブロック上に表示されます。
```js:title=example.js
... 省略
```
タイトル表示は.gatsby-code-title
というclassが付与されたdiv
要素で表示されるので、見栄え調整などはこのclass名を利用します。
任意のclassを付与したい場合は、gatsby-config.js
での呼び出し時にclassName
のオプションを指定すれば可能です。