記事一覧

gpdf でテーブルに縞模様(ゼブラ)の行を入れるには?

template.TableStripe を渡すだけ。gpdf が偶数行に背景色を塗ってくれる。行ループも手動スタイル指定も不要。

質問を言い換えると

請求書、取引履歴、ログ — 5 行を超えるテーブルを描くと、目線が次の行を見失う。Bootstrap で言う .table-striped、つまり 1 行おきにグレーが乗る縞模様を gpdf でも入れたい。行ループは書きたくない。

結論

c.Table(header, rows, template.TableStripe(pdf.RGBHex(0xF5F5F5)))

これだけ。gpdf が交互配色を担当する。ヘッダーは縞の対象外で、ボディ行のみが対象。1 行目はそのまま、2 行目に色、3 行目そのまま、4 行目に色、と続く。

動くコード

package main

import (
    "log"
    "os"

    "github.com/gpdf-dev/gpdf"
    "github.com/gpdf-dev/gpdf/document"
    "github.com/gpdf-dev/gpdf/pdf"
    "github.com/gpdf-dev/gpdf/template"
)

func main() {
    doc := gpdf.NewDocument(
        gpdf.WithPageSize(gpdf.A4),
        gpdf.WithMargins(document.UniformEdges(document.Mm(20))),
    )

    brand := pdf.RGBHex(0x1A237E)     // ヘッダー背景
    stripe := pdf.RGBHex(0xF5F5F5)    // 1 行おきの縞

    page := doc.AddPage()
    page.AutoRow(func(r *template.RowBuilder) {
        r.Col(12, func(c *template.ColBuilder) {
            c.Text("第 1 四半期 売上", template.FontSize(20), template.Bold())
            c.Spacer(document.Mm(4))

            c.Table(
                []string{"商品", "地域", "数量", "売上"},
                [][]string{
                    {"Laptop Pro 15",  "国内",  "120", "¥15,580,000"},
                    {"Wireless Mouse", "EU",   "640", "¥1,920,000"},
                    {"USB-C Hub",      "APAC", "410", "¥2,050,000"},
                    {"Monitor 27\"",   "国内",  "180", "¥7,200,000"},
                    {"Keyboard",       "EU",   "320", "¥2,560,000"},
                    {"Webcam HD",      "APAC", "260", "¥2,340,000"},
                },
                template.ColumnWidths(40, 20, 15, 25),
                template.TableHeaderStyle(
                    template.TextColor(pdf.White),
                    template.BgColor(brand),
                ),
                template.TableStripe(stripe),
            )
        })
    })

    data, err := doc.Generate()
    if err != nil {
        log.Fatal(err)
    }
    if err := os.WriteFile("sales.pdf", data, 0o644); err != nil {
        log.Fatal(err)
    }
}

go run main.go。ボディ 6 行のうち 3 行に色が入り、ヘッダーは紺地に白文字。月曜の朝に Slack に貼られる、あの形。

交互配色の仕組み

内部では、ボディ行を i (0 始まり) で走査し、i%2 == 1 の行に縞色を塗っている。ヘッダーは別スライスなのでカウント対象外。

ボディ行インデックス (0 始まり)見た目縞?
01 行目なし
12 行目あり
23 行目なし
34 行目あり
.........

Bootstrap と同じパリティ。1 行目はクリーンで、縞は視覚的な「休符」として効く。白の行を読み、次は薄く色がついた行、また白、と目が跳ねる。

パリティを反転させる(奇数行ではなく偶数行に色を入れる)オプションはない。どうしても反転したいなら body の先頭に空行を足す手はあるが、まずやらない。誰も望んでいない見た目になる。

色の選び方

縞の本質は 目立たせないこと。文字と競う色を選んだ瞬間、縞は機能しない。

pdf.RGBHex(0xF5F5F5) // 柔らかい暖色グレー。Bootstrap 既定値の近辺
pdf.RGBHex(0xFAFAFA) // さらに薄く、小さい文字ではほぼ気づかない
pdf.RGBHex(0xEEF2FF) // ブランド色のごく薄い派生 (ヘッダーが同系統色なら良い)
pdf.Gray(0.96)       // グレースケール。PDF/A 出力で数バイト削れる

彩度の高い色は避ける。彩度 60% の青は「この行は選択中・重要」というシグナルになり、視線を逐一止めてしまう。それは縞模様の目的(行をまたぐ視線移動を助ける)と逆方向だ。

ダークテーマ(社内向けスライド型レポートなどで稀にある)なら、0x1A1A1A のページに pdf.RGBHex(0x202020)。コントラスト差を低く抑えるのは同じ。

罫線と組み合わせる

短いテーブルなら縞だけで十分。会計帳票のような密度の高い表では WithTableCellBorder でセル間にヘアラインを引くと締まる:

hairline := template.Border(
    template.BorderWidth(document.Pt(0.5)),
    template.BorderColor(pdf.Gray(0.85)),
)

c.Table(header, rows,
    template.ColumnWidths(40, 20, 15, 25),
    template.TableHeaderStyle(
        template.TextColor(pdf.White),
        template.BgColor(brand),
    ),
    template.TableStripe(pdf.RGBHex(0xF5F5F5)),
    template.WithTableCellBorder(hairline),
)

ヘアライン + 薄い縞 = 経理が出してくる Excel 印刷プレビューの定番フォーマット。罫線は縞より薄くする。縞が主役で罫線は補助、の順序を崩さない。

外枠だけ欲しければ WithTableCellBorder の代わりに WithTableBorder を使う。

10 分溶かす落とし穴

  • 色の値域を間違えるpdf.RGB(245, 245, 245) は真っ黒になる。コンストラクタは 0.0〜1.0 を要求する。CSS 感覚で書きたいなら pdf.RGBHex(0xF5F5F5) を使う。
  • ヘッダーに縞をかけようとするTableStripe はヘッダーに触れない。ヘッダーに色を入れたいなら TableHeaderStyle(template.BgColor(...)) で別物。これを混同して「ヘッダーに色が乗らない」と数十分悩むのはあるあるだ。
  • 2 色交互にしたい。gpdf は縞色を 1 つしか取らない。white → gray → blue の 3 色ローテーションは仕様にない。実装すれば書けるが、読みづらいだけなので入れていない。
  • 3 行のテーブルに縞を入れる。縞模様は 4〜5 行以上ないと効果が出ない。2〜3 行だと「1 セルだけ選択された」ように見える。素直に縞なしにする。

関連レシピ

gpdf を使ってみる

gpdf は Go の PDF 生成ライブラリ。MIT、ゼロ依存、純 Go の TrueType 処理。

go get github.com/gpdf-dev/gpdf

⭐ Star on GitHub · ドキュメントを読む