5.8 多段組み (*)

Pandoc の Markdown はスライド文書に対する多段レイアウトをサポートしていますが, 他のタイプの文書ではサポートしていません. このレシピでは通常の HTML 文書や LaTeX 文書での多段レイアウトを使う方法を紹介します22. これは knitr の issue https://github.com/yihui/knitr/issues/1743 での Atsushi Yasumoto23 の解決策に着想を得ました.

考慮する必要があるのが HTML 出力のみなら話はかなり単純です. 任意の HTML 要素を横に並べて表示するのはCSS を使えば比較的簡単にできるからです. コードチャンクのテキスト出力を横に並べるだけならば, もっと簡単になります. 以下は1つ目の例です.

---
output: html_document
---

```{r attr.source="style='display:inline-block;'", collapse=TRUE}
1:10  # 1 から 10 の数列
10:1  # その逆順
```

CSS 属性 display: inline-block; は, コードブロックの出力 (つまり HTML タグの <pre> です) をインライン要素として表示しなさいという意味です. デフォルトではこれらのブロックはブロックレベル要素 (つまり display: block;) として表示され, 行を丸ごと占有します. チャンクオプション collapse = TRUE はテキスト出力を R ソースコードブロックと結合することを意味するので, ソースとテキスト出力が同じ <pre> ブロックに配置されます.

HTML 出力時に任意の順で横に並べたい場合, Pandoc の fenced Div. を使うことができます. “Div” は HTML タグの <div> に由来しますが, 任意のブロックやコンテナと解釈できます. Div の開始と終了は は3つ以上のコロン (例: :::) です. より多くのコロンの Div は, よりコロンの少ない Div を含むことができます. fenced Div の重要で有用な機能は, これに属性を付与できるということです. 例えば CSS 属性 display: flex; を外側のコンテナに適用できるので, 内側のコンテナは横並びに配置されます.

---
output: html_document
---

:::: {style="display: flex;"}

::: {}
ここは **最初の** Div です.

```{r}
str(iris)
```
:::

::: {}
こっちは右側に配置されるブロックです.

```{r}
plot(iris[, -5])
```
:::

::::

上記の例では外側の Div (::::) は2つの Div (:::) を含んでいます. この中にさらに Div を追加することもできます. とても強力な CSS 属性 display: flex; (CSS Flexbox) についてもっと知るためには https://css-tricks.com/snippets/css/a-guide-to-flexbox/ というガイドを読めばよいでしょう. CSS グリッド (display: grid;) もまた強力で, 上記の例にも使えます. もし試してみたいなら, display: flex;display: grid; grid-template-columns: 1fr 1fr; grid-column-gap: 10px; に置き換えてみてください. グリッドレイアウトについてもっと知りたければ, https://css-tricks.com/snippets/css/complete-guide-grid/ のガイドを見てください.

HTML でも LaTeX でも同じように使えるレイアウトにしたいのなら, よりトリッキーになります. 以下に HTML, LaTeX そして Beamer で使える用例の全容を示します.

---
output:
  pdf_document: 
    latex_engine: lualatex
    keep_tex: true
    includes:
      in_header: columns.tex
  html_document: 
    css: columns.css
  beamer_presentation: 
    keep_tex: true
    latex_engine: lualatex
    includes:
      in_header: columns.tex
documentclass: "`r if(knitr::opts_knit$get('rmarkdown.pandoc.to') == 'beamer') 'beamer' else 'ltjsarticle'`"
mainfont: 'Noto Sans CJK JP'
---

# 二段組み

以下は 3つの子要素の Div を横並びに持つ Div コンテナです. 中央の Div は空で, 左右の Div の間に空白を作るためだけに存在します.

:::::: {.cols data-latex=""}

::: {.col data-latex="{0.55\textwidth}"}
```{r, echo=FALSE, fig.width=5, fig.height=4}
par(mar = c(4, 4, .2, .1))
plot(cars, pch = 19)
```
:::

::: {.col data-latex="{0.05\textwidth}"}
\ 
<!-- 段どうしのセパレータとして機能するだけの空の Div (空白入り) -->
:::

::: {.col data-latex="{0.4\textwidth}"}
左側の図は `cars` データを表しています.


> いろはにほへと ちりぬるを
わかよたれそ つねならむ
うゐのおくやま けふこえて
あさきゆめみし ゑひもせす

:::
::::::
HTML, LaTeX, Beamer で動作する二段組み

図 5.3: HTML, LaTeX, Beamer で動作する二段組み

5.3 がその出力です. この例では外側の .cols クラスを持つ Div と, 内側に .col クラスを持つ3つの Div を使っています. HTML 出力では, 外部 CSS ファイル columns.css を導入し, その中で Flexbox レイアウトを外側の Div に適用しているので, 内側の Div が横並びになります.

.cols {display: flex; }

LaTeX 出力 (pdf_document) では, columns.tex に含まれている「あまり行儀の良くない裏ワザ」をLaTeX プリアンブルに適用し, LaTeX 環境 colscol を定義しなければなりません.

\newenvironment{cols}[1][]{}{}

\newenvironment{col}[1]{\begin{minipage}{#1}\ignorespaces}{%
\end{minipage}
\ifhmode\unskip\fi
\aftergroup\useignorespacesandallpars}

\def\useignorespacesandallpars#1\ignorespaces\fi{%
#1\fi\ignorespacesandallpars}

\makeatletter
\def\ignorespacesandallpars{%
  \@ifnextchar\par
    {\expandafter\ignorespacesandallpars\@gobble}%
    {}%
}
\makeatother

col 環境が特に複雑な主な理由としては, LaTeX 出力で Pandoc は各 Div でいつも段落を改めるので, この改段を除去しなければならないからです. そうしないと Div を横並びに配置することはできません. このハックは https://tex.stackexchange.com/q/179016/9128 から借用しました.

Beamer 出力でも columns.tex で同じハックを適用しています. Pandoc は スライドショー用に ::: {.columns}, ::: {.column}, ::: {.incremental} といった特別な Div を提供していることに注意してください. これらは特別な意味を持つため, この節のような方法で Div を LaTeX 環境に変換するときには, これらのタイプの Div使わないように注意しなければなりません. columnscolumn という名前の Div タイプを使わず, cols, col 使ったのは, これが理由です.

fenced Div についてより詳しく知りたいなら, 9.6節を見てください.


  1. 訳注: 二段組にしたいのが PDF 限定であれば, YAML フロントマターのみで簡単に制御できるかもしれません (6.2節参照).↩︎

  2. 訳注: @atusy のこと↩︎