Marpの見た目を調整する際の備忘録

[Marp]:https://marp.app/
普段Markdownでメモを取っている場合、それを会議などで人に見せる場合には [Marp] を使うと便利ですが、その際にカスタムテーマを使いたくなる場合があります。

この記事は、主にカスタムテーマを比較的マシな見た目で作るための備忘録です。

## カスタムテーマ (CSS) 関係

### ヘッダやフッタは基本的にSectionに対するBackground指定でごまかしたほうが見た目の調整が楽

`header`、`footer` などのディレクティブを使ってヘッダ、フッタを描画しようとするとうまく行かない場合が多いので、会社のロゴなどをヘッダ、フッタに入れる場合は単純に `section` 要素に対する背景（CSS `background` プロパティ）として指定したほうが `background-position` などで絶対位置の調整がしやすく、楽です。

この際、`background` は複数指定できることを利用すると比較的複雑なことが可能です。

例えば背景と別に、右上にロゴを入れたい場合は以下のような感じになります：
```CSS:CSS
section {
  background-image: 
    url(URL_TO_HEADER_LOGO) /* ロゴのURL */,
    url(URL_TO_MAIN_BACKGROUND) /* メイン背景のURL */;
  background-position: 
    right 30px top 30px /* ロゴの位置（右上、オフセットあり） */,
    top left /* メイン背景の基準位置 */;
  background-size:
    100px 30px, /* ロゴのサイズ */
    1280px; /* メイン背景のサイズ */
  background-repeat: no-repeat /* 共通 */;
}
```
同じ表現を `background` プロパティでまとめて指定することもできます（記法が若干トリッキーです):
```CSS:CSS
section {
  background:
    top 30px right 30px/100px 30px url(URL_TO_HEADER_LOGO) /* ロゴの設定 */,
    top left/1280px url(URL_TO_MAIN_BACKGROUND) /* メイン背景画像の設定 */;
  background-repeat: no-repeat /* 共通 */;
}
```

この際、以下の点に留意して下さい：
- 複数の `backround` 画像指定がある場合、先に出てきた指定のが方が上のレイヤになります（＝[Z-index](https://developer.mozilla.org/ja/docs/Web/CSS/z-index)が大きい）。このため、ロゴのようなもの→背景の順序で記載して下さい。
- `section` のサイズは固定です。デフォルトでは 1280x720px になっていますので、背景画像のサイズ指定の基準として下さい。
- `background-size` の指定は CSS 標準の通りですので：
    - 値を1つだけ書いた場合は幅の指定として扱われ、高さは元画像のアスペクト比を保存するサイズとなります。
    - 値を2つ書いた場合は、幅と高さを指定したものとして扱われ、画像のアスペクト比も変更されます。

参考: 
- Marpit > Theme CSS > Styling > [Slide size](https://marpit.marp.app/theme-css?id=slide-size)
- marp-core > [size global directive](https://github.com/marp-team/marp-core#size-global-directive)
- mdn web docs > [background](https://developer.mozilla.org/ja/docs/Web/CSS/background)

### 単色の画像を使った `background` 指定によってボーダーを描くこともできる

単色の画像を用意して、それを 画面幅 &times; ボーダーの高さ のサイズで背景指定すればある種のボーダーとしても使えます。
```CSS:CSS
section {
  background:
    bottom 72px left 30px/100px url(LOG_IMAGE),
    bottom 72px right 30px/1220px 1px url(color.svg) /* 擬似ボーダー */,
    center/cover url(bg.svg);
}
```
上の例では2つ目の background 指定がボーダーとして描画されます。

また、color.svg はこんな感じになります:
```xml:color.svg
<svg xmlns="http://www.w3.org/2000/svg" style="background:#AAA"></svg>
```

### 特定のページだけスタイルを変えたい場合は、`class` を使うのが一般的な手法

```CSS:CSS
section {
   /* ... 通常セクションの設定 */
}
section.top {
   /* ... トップページの設定 */
}
```

```markdown:Markdown
# トップページ
<!-- _class: top -->

内容

---

# 続きのページ

...
```

この際、クラスの指定は `_class` だと1ページだけ、`class` だとそれ以降のページ全てに影響します。

#### 関連: class が適用されたセクションにある要素（HTML Element）のCSSセレクタ

おそらくベースになっているスタイルに依存しますが、`class: top` を指定しているセクションで、`h2`要素のスタイルを変更したい場合のCSSセレクタは:

- `.top h2 { /* some setting */ }` の形式だと反映されません。
- `section.top h2 { /* some setting */ }` の形式だと設定が反映されます。
- このため `.top h2 { some: setting !important; }` のように `!important` 指定を行って優先度を高くする方が良いでしょう。 :star:

### コードのフォントの変更するためのCSSセレクタ

1. `` `monospace` `` の形式の表記のフォントを変えるためのCSSセレクタは `code`.
1. ```` ``` ```` で囲われたコードブロックのフォントを変える場合、前述の `code` セレクタだけではうまく指定できないので、`code *` も追加したほうが良い。
1. また、`font-family` 等の場合、`!important` ルールも指定しないと反映されない場合がある（ベースのCSSが `default` の場合など）

```CSS:CSS
code, code * { font-family: "Monaco", "Courier New", monospace !important; }
```

### ページ番号（Pagenation）のCSSセレクタ

[Pagination]:https://marpit.marp.app/theme-css?id=pagination
Pagination のスタイルは `section::after` により設定できる。

参考: Marpit > Theme CSS > [Pagination]

#### ページ番号表記の変更

`section::after` の `content` を変更するとページ番号の表記などを変更できます。

"1 / 10" のような表示にしたい場合の例:

```CSS:CSS
section::after {
    content: attr(data-marpit-pagination) ' / ' attr(data-marpit-pagination-total);
}
```

#### ページ番号をフッタの中央に配置する

![_Users_ariga_GitHub_marp_theme_study_sample.html (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423595/088dabd0-4a0d-0c98-cf97-aaa3a2f0a778.png)

上の図のように、ページ番号をフッタ部分の中央に置きたい場合、
CSS [calc()](https://developer.mozilla.org/ja/docs/Web/CSS/calc) などの機能を使って、ページ番号の箱である `section::after` をページいっぱいまで広げて、箱を `text-align: center` にすれば所望の見た目になります。

```CSS:CSS
section::after {
	right: 30px; /* works as footer margin */
	width: calc(100% - 60px);
	text-align: center;
	border-top: solid black 1px;
	padding-top: 15px;
}
```

上の例ではついでにボーダーも表示している。

### テーマ内で使う画像は埋め込んでしまったほうが楽

カスタムテーマのCSS中で相対リンクの画像参照（例: `url(hoge.png)`）を行うと、変換時には CSS の場所を起点にした参照ではなく、変換対象の Markdown を起点にした参照が行われるようです（参考: [Marp theme folder hierarchy #181](https://github.com/marp-team/marp-vscode/issues/181)）。
このためテーマを色んな所で使い回すのであれば、画像データはCSSの中に埋め込んでしまうほうが取り回しが良く、おすすめです。

1. 画像の埋め込みには [data URI](https://ja.wikipedia.org/wiki/Data_URI_scheme) が便利です。 

    ```
    例) url(data:image/png;base64,xxxxxxxx)
    ```

1. 埋め込む際、画像は [openssl](https://linux.die.net/man/1/openssl) のサブコマンド `base64` や GNU [Coreutils](https://www.gnu.org/software/coreutils/) や MacOS に含まれている `base64` コマンドなどを使ってBase64変換することができます。`openssl` コマンドを使う場合：

    ```bash:コマンド
    openssl base64 -A -in SOME_IMAGE.png -out SOME_IMAGE.b64
    ```

1. 画像を複数箇所で参照する場合はCSSの [カスタムプロパティ](https://developer.mozilla.org/ja/docs/Web/CSS/Using_CSS_custom_properties) を使うと良いでしょう。

    ```CSS:CSS
    :root {
      --bg-image: url(data:image/png;base64,xxxxxxxxxxxxxxxx);
    }
    section {
      background-image: var(--bg-image);
    }
    ```

## その他のTips

### ページ番号付の設定は、Markdown側に記載する必要がある（っぽい）

詳細確認中だが、`.marprc.yml` などに `pagination` ディレクティブを記載しても反映されないような気がする。

### YAMLのFront Matterを書くと、他のツールとの整合が難しいので、コメントに入れるほうが良い

Marpへの設定は、以下のようにYAML形式の Front Matter としても記載できるが、この書き方だと他のツールでFront Matterが表示されたりしてちょっと不便です。

```markdown:MarkdownのFront Matter
---
title: テスト
---
```

副作用を避けたいならコメント中に入れるほうが無難でしょう。

```markdown:Front Matterをコメント内に記載する例
<!-- title: 一行で書く場合 -->
<!-- 
title: 複数行にする場合
class: hoge
-->
```

### YAML形式のディレクティブ表記の場合、`:` のあとにスペースが必要

Front Matter は YAML の [ハッシュ](https://magazine.rubyist.net/articles/0009/0009-YAML.html#%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5) という記法を利用しているので、文法上コロン `:` のあとにスペースが必要なので気をつけましょう。

例えば `_class:top` と書くと設定は反映されないが、`_class: top` と書くと反映されます。

### ページ区切りをあまり気にしないで記事を書きたい場合は `headingDivider` が便利

1. `headingDivider` ディレクティブで自動的にページ切り替えになる見出しレベルを設定しておくと書き散らす場合には楽。個人的には `h1` はタイトルのみに利用しているので、`headingDivider: 2` に設定しています。

2. `headingDivider` ディレクティブも Local 扱いなので、ファイル中に記載する必要があるようです。

3. `headingDivider` ディレクティブを設定している場合に、ページ内の設定を `_class` 指定などで変える場合は以下のような記載方法になります。

    ```markdown:Markdown
    ## Heading
    <!-- _class: something --> 
    このセクションの内容が `something` 扱いになる。
    ```

### Fragmented Listが鬱陶しい場合は、Fragmentされない表記を使う

Marpにはリストがあった場合にそれをクリックごとに表示するPowerPointのアニメーションに対応する機能（Fragmented List）があるが、これが有効になる表記と、そうでない表記があるので使い分けよう。

```markdown:Markdown
* Fragment
* List

- Not Fragmented
- List

1) Fragmented
1) Numbered List

1. Not Fragmented
1. Numbered List
```

### 画像は Split Backgrounds + 透過画像によるマージンを使うと楽

[Split Backgrounds]:https://marpit.marp.app/image-syntax?id=split-backgrounds
通常の `![alternative](url)` 表示による画像挿入はレイアウトの調整が難しいので、[Split Backgrounds] の機能を使って、左寄せないし右寄せにしたレイアウトを使うほうが良さそう。

この場合、基本的に画面端いっぱいまで画像が表示される（下図）
![sample.003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423595/df171f41-30b4-94b8-2f82-c24b4a31ef41.png)


もし画像の端にマージンを取りたいのであれば透過機能のある画像形式（PNGなど）を使って画像の方に透明なマージンを設定すると期待に近いレイアウトを実現できます。
![sample.004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423595/d5b76386-c901-e62b-7cbb-e5e7ec4b3b4d.png)

上の例では左側に100pxの透明なマージンを設定した900x800pxの画像（`image_margin_left.png`）を表示しています。

```CSS:CSS
![bg left:30% contain](image_margin_left.png)
```

#### 別解: CSSにより Split Backgrounds にマージンをつける方法

Split Backgrounds の画像は、attribute `data-marpit-advanced-background-split` を持つ `section` 要素中の attribute `data-marpit-advanced-background-container` を持つ `div` 要素の中に `figure` 要素として敷き詰められています。

![marp-background-structure (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423595/b41c2a02-acde-93be-cd60-1e13d3d33617.png)

そのため、以下のような CSS を指定して、`figure` が入っている `div` のサイズとマージンを調整すると画像のページに対するマージンをコントロールできます:

```CSS:CSS
section[data-marpit-advanced-background-split="right"] >
div[data-marpit-advanced-background-container] {
	margin-top: 30px !important;
	/* margin-left は既存の設定を再利用する */
	width: calc(var(--marpit-advanced-background-split) - 30px) !important;
	height: calc(100% - 108px) !important;
}
```

この際、`![bg right:N%]` で指定した画像幅（画面の幅に対する割合）の情報が変数 `--marpit-advanced-background-split` から取得できる点が重要です。

![split-background-ex2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423595/9b819a2d-882b-a897-23ee-9b0e89e8d065.png)

ただし、この部分の挙動はドキュメントに記載されていないので、特に断りなく仕様変更が行われる可能性があることを留意して下さい。

## 環境など

動作確認は、marp-cli 1.5.0 MacOS (Homebrew) で行いました。
実験で使った Markdown や CSS は [GitHub](https://github.com/aikige/marp_theme_study) に置いてあります。