📐

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

2021/12/07に公開

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

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

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

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

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

この際、background はコンマ区切りで複数指定できることを利用すると比較的複雑なことが可能です。

例えば背景と別に、右上にロゴを入れたい場合は以下のような感じになります:

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
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が大きい)。このため、ロゴのようなもの→背景の順序で記載して下さい。
  • section のサイズは固定です。デフォルトでは 1280x720px になっていますので、背景画像のサイズ指定の基準として下さい。
  • background-size の指定は CSS 標準の通りですので:
    • 値を1つだけ書いた場合は幅の指定として扱われ、高さは元画像のアスペクト比を保存するサイズとなります。
    • 値を2つ書いた場合は、幅と高さを指定したものとして扱われ、画像のアスペクト比も変更されます。

参考:

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

単色の画像を用意して、それを 画面幅 × ボーダーの高さ のサイズで背景指定すればある種のボーダーとしても使えます。

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 はこんな感じになります:

color.svg
<svg xmlns="http://www.w3.org/2000/svg" style="background:#AAA"></svg>

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

CSS
section {
   /* ... 通常セクションの設定 */
}
section.top {
   /* ... トップページの設定 */
}
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.
  2. ``` で囲われたコードブロックのフォントを変える場合、前述の code セレクタだけではうまく指定できないので、code * も追加したほうが良い。
  3. また、font-family 等の場合、!important ルールも指定しないと反映されない場合がある(ベースのCSSが default の場合など)
CSS
code, code * { font-family: "Monaco", "Courier New", monospace !important; }

ページ番号(Pagenation)のCSSセレクタ

Pagination のスタイルは section::after により設定できる。

参考: Marpit > Theme CSS > Pagination

ページ番号表記の変更

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

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

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

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

_Users_ariga_GitHub_marp_theme_study_sample.html (1).png

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

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)。
このためテーマを色んな所で使い回すのであれば、画像データはCSSの中に埋め込んでしまうほうが取り回しが良く、おすすめです。

  1. 画像の埋め込みには data URI が便利です。

    例) url(data:image/png;base64,xxxxxxxx)
    
  2. 埋め込む際、画像は openssl のサブコマンド base64 や GNU Coreutils や MacOS に含まれている base64 コマンドなどを使ってBase64変換することができます。openssl コマンドを使う場合:

    コマンド
    openssl base64 -A -in SOME_IMAGE.png -out SOME_IMAGE.b64
    
  3. 画像を複数箇所で参照する場合は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のFront Matter
---
title: テスト
---

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

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

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

Front Matter は YAML の ハッシュ という記法を利用しているので、文法上コロン : のあとにスペースが必要なので気をつけましょう。

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

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

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

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

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

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

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

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

Markdown
* Fragment
* List

- Not Fragmented
- List

1) Fragmented
1) Numbered List

1. Not Fragmented
1. Numbered List

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

通常の ![alternative](url) 表示による画像挿入はレイアウトの調整が難しいので、Split Backgrounds の機能を使って、左寄せないし右寄せにしたレイアウトを使うほうが良さそう。

この場合、基本的に画面端いっぱいまで画像が表示される(下図)
sample.003.png

もし画像の端にマージンを取りたいのであれば透過機能のある画像形式(PNGなど)を使って画像の方に透明なマージンを設定すると期待に近いレイアウトを実現できます。
sample.004.png

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

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

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

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

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

環境など

動作確認は、marp-cli 1.5.0 MacOS (Homebrew) で行いました。
実験で使った Markdown や CSS は GitHub に置いてあります。

https://github.com/aikige/marp_theme_study

Discussion