基本概念

Imposia が生まれた理由

ブラウザー出版が繰り返しぶつかる問題と、それに対して Imposia が選んだ設計上の賭けを説明します。

Imposia の出発点は、再現しやすく直しにくい失敗です。コンテンツを編集して印刷するアプリを作ると、「同じはず」の文書が 3 つできあがります。

同じはずの文書が 3 つに分かれる

典型的なブラウザー出版機能は、次の順序で育ちます。

まずエディターがコンテンツを描画し、人が編集できるようにします。次に印刷結果のプレビューが求められ、プレビューが追加されます。多くの場合、別のコンテナーと別の CSS へコンテンツを複製する形です。最後に印刷を実際に動かす必要が出て、印刷経路が現れます。これはコンテンツをもう一度組み立て直すもので、サーバーやヘッドレスブラウザーで動くこともあります。

こうして 3 つの面がそれぞれ自分のツリーを計測するようになります。一致を強制するものは何もなく、ずれていきます。

  • プレビューは 12 ページと言い、PDF は 13 ページある。
  • 表ヘッダーが画面では正しく繰り返され、紙では繰り返されない。
  • 「7 ページを参照」が、ある成果物では 7 ページを、別の成果物では 8 ページを指す。
  • あるユーザーでは再現し、別のユーザーでは再現しないバグが生まれる。ずれ方がフォント、タイミング、どの面が先に描画されたかに依存するからです。

これらはレイアウトのバグではありません。レイアウトの決定者が 3 つあり、どれを正とするかの規則がないことの帰結です。

よくある答えと、それぞれの代償

この分野には良いツールがあります。その多くは、1 つの決定者を選び、その代わりに何かを手放すことで衝突を解決します。

方式すること手放すもの
サーバーレンダラー(ヘッドレスブラウザー、または専用エンジン)唯一のレンダラーをクライアントの外に置くプレビューは別の場所で作られた結果の写しになるため、ユーザーが編集している内容と食い違う余地が残る
独自コンポーネントを持つ別の文書レンダラー自分で制御するレイアウトツリーから決定的な出力を得る既存の HTML と CSS が使えず、コンテンツを二重に作ることになる
画面のラスタライズ画面にあるものがそのまま成果物になる本当のページ分割ではなく、テキストがテキストでなくなる

いずれも合理的なトレードオフで、多くの製品にとって正しい選択です。サーバーで生成した PDF バイトが必要なら、Imposia よりヘッドレスブラウザーの方が適しています。本ドキュメントでもそう案内します。

Imposia の賭け

Imposia は別のトレードオフを選びます。ブラウザーが所有する 1 つの文書を、すべての面が参照するという賭けです。

その帰結として、Imposia は組版エンジンを持ちません。組版はおおよそ 4 つの層に分かれます。

  1. グリフ整形 — カーニング、リガチャ、文字体系ごとの結合
  2. 行分割 — 行の終わり、ハイフネーション、CJK の規則
  3. ブロックレイアウト — マージン、フロート、flex、grid、テーブル
  4. ページ分割 — 紙面が尽きたとき、内容をどこで切るか

1〜3 層は、ブラウザーが数十年をかけて磨いてきた、際立って得意な領域です。4 層目だけは、紙があるときにしか存在しないため、ブラウザーはほとんど実装していません。

そこで Imposia は 4 層目を実装し、残りをブラウザーに委ねます。コンテンツを実際のブラウザーフレームで描画し、ブラウザーが実際に作り出した結果を計測し、その計測値からページを切り出します。

この方式で得られるもの

日本語や韓国語の行分割規則、アラビア文字の整形、絵文字シーケンス、可変フォント、そしてブラウザーが対応するすべての CSS レイアウト機能がそのまま動きます。ここで実装したからではなく、ブラウザーから取り上げなかったからです。

この方式の代償

この選択には実際の欠点があります。それを伏せれば、この先のドキュメント全体の信頼が下がります。

  • 計測は無料ではありません。 切る位置を決めるには、内容を追加し、ブラウザーにジオメトリを問い合わせ、ときには取り消す必要があります。閉じたモデルでレイアウトを計算するより遅くなります。
  • エンジンはブラウザーのものです。 行分割は Chromium、Firefox、WebKit で異なるため、ページ数も異なることがあります。構造の基準は Chromium です。他のエンジンでは API、隔離、ライフサイクル、書き出しの動作を検証しており、同一の出力は検証対象ではありません。
  • CSS フラグメンテーションは完全には解けていません。 テーブル、flex、grid、段組みは文書化されたサブセットとして対応します。サブセット外の内容は黙って近似される代わりに、分割されずにそのまま残り、型付きの警告を発します。

Imposia がやらないと決めていること

この境界は製品の欠落ではなく、製品の一部です。

  • PDF バイトを返しません。 print() は完成したページをブラウザー自身の印刷ダイアログに渡し、読者はそこでプリンターまたはPDF に保存を選びます。PDF レンダラーを追加すれば、他の 3 つと食い違い得る 4 つ目の文書が生まれます。それは、このライブラリが取り除くために存在する問題そのものです。
  • Node や CLI のレンダラー、サーバー書き出しを持ちません。 実行環境の境界はブラウザーです。
  • エンジン間で同一のページ数を約束しません。 ブラウザーが 1〜3 層を所有する限り守れない約束であり、守れない約束はしません。

Imposia は適した道具か

向いている場合

人がコンテンツを見て編集する React アプリがあり、印刷または PDF の結果が、いま見ているものと一致しなければならない。

向いていない場合

ブラウザーで誰もプレビューしないコンテンツから、サーバー上で PDF バイトを生成する必要がある。

前者が当てはまるなら、次のステップは最初のページを作るです。単一文書の規則が実行時にどう強制されるかを知りたい場合は、出版モデルを読んでください。

On this page