CSSフラグメンテーションでボックスを壊す
公開: 2022-03-10この記事では、CSSフラグメンテーション仕様を紹介します。 聞いたことがないかもしれませんが、印刷スタイルシートを作成してコンテンツがページ間で分割される場所を制御したい場合、または複数列のレイアウトで図が列間で分割されないようにしたい場合は、これに遭遇しました。
multicolで報告される問題は、実際にはブラウザによるフラグメンテーションのサポートに関する問題であることがよくあります。 この仕様に含まれているプロパティの概要を説明した後、ブラウザサポートの現在の状態と、マルチ列プロジェクトや印刷プロジェクトで同様に機能させるために実行できるいくつかのことについて説明します。
フラグメンテーションとは何ですか?
CSSの断片化は、コンテンツがさまざまなボックスに分割されるプロセスを表します。 現在、Web上で断片化が発生する可能性のある場所が2つあります。ドキュメントを印刷するときと、複数列のレイアウトを使用するときです。 これら2つのことは本質的に同じです。 Webページを印刷(またはPDFに保存)すると、コンテンツは、コンテンツの印刷に必要な数のページに断片化されます。
multicolを使用すると、コンテンツは列に断片化されます。 各列ボックスは、ページ化されたコンテキストのページのようなものです。 列のセットをページのセットによく似ていると考える場合、multicolとその中での断片化のしくみについて考えるのに役立つ方法です。
CSS Fragmentation Specificationを見ると、3番目の断片化されたコンテキストが言及されていることがわかります—そのコンテキストはRegionsです。 リージョンの現在使用可能な実装がないため、この記事ではそれを扱いませんが、代わりに、作業で遭遇する可能性のある2つのコンテキストを調べます。
ブロックボックスとインラインボックス
この記事では、ブロックボックスについて詳しく説明します。 ページのすべての要素にボックスがあります。 これらのボックスの一部は、段落、リストアイテム、見出しなどのブロックとして配置されます。 これらは、ブロックフォーマットコンテキストに参加していると言われます。 その他は、段落内の単語、スパン、アンカー要素などのインラインです。 これらは、インラインフォーマットコンテキストに参加します。 簡単に言えば、私がブロックボックスについて言及するとき、私は段落のようなものの周りのボックスについて話している。 断片化を処理するときは、どの種類のボックスを処理しているかを知ることが重要です。
ブロックとインラインレイアウトの詳細については、MDNの記事「通常のフローでのブロックとインラインレイアウト」を参照してください。 これは、おそらく私たち全員がある程度理解していることの1つですが、以前の用語に遭遇したことはないかもしれません。
休憩の管理
印刷スタイルシートを作成する場合でも、特定の印刷ユーザーエージェントを使用してPDFを作成する場合でも、multicolを使用する場合でも、次のような問題が発生することがあります。
以下のマルチ列の例では、3つの列として表示しているコンテンツがいくつかあります。 コンテンツの中央には、2つの列に分割されているボックス化された領域があります。 私はこの振る舞いを望んでいません—私は箱を一緒に保ちたいです。
これを修正するために、プロパティbreak-inside: avoid
をボックスに追加します。 break-inside
プロパティは、要素がフラグメント化されたコンテキストにある場合に、要素内のブレークを制御します。 このプロパティをサポートするブラウザでは、ボックスは列の1つにとどまります。 列のバランスが崩れるように見えますが、一般的には、ボックスアウトが列に分割されるよりも優れています。
break-inside
プロパティは、フラグメンテーション仕様で詳しく説明されているプロパティの1つです。 プロパティの完全なリストは次のとおりです。
-
break-before
-
break-after
-
break-inside
-
orphans
-
widows
-
box-decoration-break
ブラウザで実際に何が起こるかを説明する前に、これらがどのように機能するかを見てみましょう。
break-before
およびbreak-after
プロパティ
ブロックレベルのボックス間のブレークを制御する2つのプロパティがあります。 break-before
とbreak-after
です。 h2
の後に2つの段落が続く場合<p>
3つのブロックボックスがあり、これらのプロパティを使用して、見出しと最初の段落の間、または2つの段落の間の区切りを制御します。
プロパティは、前後に分割する要素を対象とするセレクターで使用されます。
たとえば、レベル2の見出しがあるたびに、印刷スタイルシートを新しいページに分割したい場合があります。 この場合、 h2
要素でbreak-before: page
を使用します。 これにより、断片化が制御され、 h2
要素のボックスの前に常にブレークが存在するようになります。
h2 { break-before: page; }
もう1つの一般的な要件は、見出しがページまたは列の最後に表示されないようにすることです。 この場合、 avoid
値を指定してbreak-after
を使用できます。 これにより、要素のボックスの直後での破損を防ぐことができます。
h1, h2, h3, h4 { break-after: avoid; }
フラグメント内のフラグメント
断片化された要素が別の要素の中にネストされている可能性があります。 たとえば、ページングされたものの中にマルチ列を配置します。 その場合、ページの区切りを制御したいが、列の区切りを制御したくない場合があります。またはその逆の場合もあります。 これが、フラグメントがページである場合にのみ、要素の前後に常にブレークを強制するpage
などの値がある理由です。 または、ページ化されたコンテキストの場合にのみ要素の前後の中断を回避する回避avoid-page
。
同じことが列にも当てはまります。 値column
を使用する場合、これは常にその要素の前後にブレークを強制しますが、マルチ列コンテキストの場合のみです。 値avoid-column
は、複数列のコンテキストでの中断を防ぎます。
レベル4仕様には、ページまたは列のすべてを突破したいことを示すalways
値があります。 ただし、仕様への最近の追加として、それは現在私たちにとって有用ではありません。
ページメディアの追加値
本や雑誌を作成している場合は、左右のページがあります。 スプレッドの左または右のページに何かを強制するために、ブレークを制御したい場合があります。 したがって、以下を使用すると、 h2
の前に1ページまたは2ページの区切りを挿入して、正しいページとしてフォーマットされていることを確認します。
h2 { break-before: right; }
垂直または右から左の言語で書かれた本は英語で書かれた本とは異なるページ進行を持っているので、ページ進行に関連するrectoとversoの値もあります。 今回は主にブラウザから何が可能かを考えているので、この記事ではこれらの値についてはこれ以上取り上げません。
break-inside
break-inside
プロパティの例はすでに見てきました。 このプロパティは、段落、見出し、divなどのブロックボックス内での分割を制御します。
壊したくないものには、上記のようなボックスアウトを含めることができます。画像、表、リストなどからキャプションを切り離したくない図です。 break-inside: avoid
てください。 列間の区切りのみを避けたい場合は、 break-inside: avoid-column
およびページ間のbreak-inside: avoid-page
使用してください。
orphans
とwidows
のプロパティ
orphans
プロパティとwidows
プロパティは、(列または新しいページが原因で)ブレークの前後に残しておく必要のある行数を処理します。 たとえば、列の最後に1行が残らないようにする場合は、タイポグラフィのようにorphans
プロパティを使用します。孤立は、ページの下部に単独で表示される段落の最初の行です。段落の残りの部分は別のページに分割されています。 プロパティは、フラグメント化されている同じ要素(この場合はmulticolコンテナ)に追加する必要があります。
.container { column-count: 3; orphans: 2; }
休憩後に列またはページの上部に表示する行数を制御するには、 widows
を使用します。
.container { column-count: 3; widows: 2; }
これらのプロパティは、段落内の単語の行などのインラインボックス間の区切りを処理します。 したがって、見出しまたは他のブロック要素が列またはページの下部に単独で存在する状況では役に立ちません。そのためには、上記で説明したブレークプロパティが必要です。
ボックスデコレーション
興味があるかもしれない最後のプロパティは、 box-decoration-break
プロパティです。 これは、2つの列ボックスまたはページの間に境界線が壊れたボックスがある状況を制御します。 境界線を基本的に半分にスライスしますか? それとも、ボックスの2つの半分のそれぞれを境界線で完全に包むようにしますか?
最初のシナリオはデフォルトであり、 box-decoration-break
プロパティをボックスでslice
するように設定した場合と同じです。
.box { box-decoration-break: slice; }
2番目の動作を取得するには、 box-decoration-break
をcloneに設定します。
.box { box-decoration-break: clone; }
フラグメンテーションのブラウザサポート
ここで、これらすべてをデモするための上記のCodePenの例がたくさんない理由と、この記事を書く主な理由がわかりました。 これらのプロパティのブラウザサポートは素晴らしいものではありません。
Princeなどの特定のユーザーエージェントを使用してPagedMediaで作業している場合は、フラグメンテーションの非常に優れたサポートを享受でき、おそらくこれらのプロパティが非常に役立つことがわかります。 マルチ列で、印刷スタイルシートを作成するか、ヘッドレスChromeなどを使用してPDFを生成するなど、Webブラウザーを使用している場合、サポートには多少のパッチがあります。 とにかくChromiumに移行するまで、最高のサポートを提供するブラウザーはEdgeであることがわかります。
フラグメンテーションプロパティをmulticolと混合し、レガシープロパティ用にいくつかの個別のデータを用意しているため、サポートの説明にはあまり役に立ちません。 そこで、MDNでプロパティとそのサポートを文書化するために行ってきた作業の一環として、実際のブラウザサポートのテストを開始しました。 以下は、そのテストに基づいたアドバイスです。
レガシーおよびベンダーのプレフィックス付きプロパティ
歴史の授業なしでは、これ以上先に進むことはできません。 断片化のサポートが本当に必要であることがわかった場合は、元々CSS2の一部であったレガシープロパティ(または存在するいくつかのプレフィックス付きプロパティ)に多少の緩和が見られる場合があります。
CSS2には、ページ分割を制御するためのプロパティがありました。 その時点ではMulticolは存在していなかったため、断片化されたコンテキストはページングされたコンテキストのみでした。 これは、3つの特定のページ分割プロパティが導入されたことを意味します。
-
page-break-before
-
page-break-after
-
page-break-inside
これらはpage-
プレフィックスのないより一般的なプロパティと同じように機能し、ボックスの前、後、および内部の区切りを制御します。 印刷スタイルシートの場合、新しいbreak-
プロパティをサポートしていない古いブラウザの中には、これらのページプレフィックス付きプロパティをサポートしているものがあります。 プロパティは、新しいプロパティのエイリアスとして扱われています。
multicol仕様の2005年の作業ドラフトには、multicolのブレークプロパティの詳細があります— column-
のプレフィックスが付いたプロパティを使用します(つまり、 column-break-before
、 column-break-after
、 column-break-inside
)。 2009年までに、これらはなくなり、ドラフトはプレフィックスなしのブレークプロパティのmulticol仕様に含まれ、最終的にCSSFragmentation仕様に組み込まれました。
ただし、一部のベンダープレフィックス付きの列固有のプロパティは、これらのプロパティに基づいて実装されました。 これらは:
-
-webkit-column-break-before
-
-webkit-column-break-after
-
-webkit-column-break-inside
Multicolでのフラグメンテーションのサポート
以下は、マルチ列コンテキストでのこれらの機能のテストに基づいています。 私は何が可能かを説明しようとしましたが、利用可能なブラウザでCodePensを見てください。
マルチコルとbreak-inside
multicolでのサポートは、 break-inside
プロパティに最適です。 Chrome、Firefox、Edge、Safariの最新バージョンはすべて、 break-inside: avoid
。 したがって、multicolを使用すると、ボックスが列間で壊れるのを防ぐことができることがわかります。
Firefoxを除くいくつかのブラウザは、 -webkit-column-break-inside
プロパティをサポートしています。これは、 avoid
値を指定して使用でき、 break-inside
をサポートしていない列間でボックスが壊れるのを防ぐことができます。
Firefoxはpage-break-inside: avoid
てください。 したがって、このプロパティを使用すると、Firefox65より前のFirefoxブラウザのボックス内での破損を防ぐことができます。
これは、multicolのボックス間の区切りを防ぎたい場合、次のCSSを使用すると、可能な限り多くのブラウザーをカバーし、可能な限り遡ることができることを意味します。
.box { -webkit-column-break-inside: avoid; page-break-inside: avoid; break-inside: avoid; }
column
の値については、ページではなく列間の区切りのみを避けたいことを明示的に指定すると、Firefoxを除くすべてのブラウザで機能します。
以下のCodePenは、これらのテストの一部をmulticolにまとめているため、自分で試すことができます。
マルチコルとbreak-before
ビフォア
要素の前での中断を防ぐには、 break-before: avoid
またはbreak-before: avoid-column
を使用できる必要があります。 回避プロパティはブラウザをサポートしていません。
Edgeはbreak-before: column
をサポートし、要素のボックスの前で常にブレークを強制します。
Safari、Chrome、およびEdgeは、 -webkit-column-break-before: always
サポートします。これは、要素のボックスの前で強制的にブレークします。 したがって、要素のボックスの前で強制的にブレークする場合は、次を使用する必要があります。
.box { -webkit-column-break-before: always; break-before: column; }
ボックスの前に休憩を防ぐことは、現在不可能な作業です。 以下のこれらのプロパティのいくつかの例を試してみることができます。
マルチコルとbreak-after
要素の後のブレークを防ぐために、それが列の下部で最後になるのを避けるために、 break-after: avoid
とbreak-after: avoid-column
を使用できる必要があります。 これらをサポートする唯一のブラウザはEdgeです。
Edgeは、 break-after: column
を使用して要素の後に強制的にブレークすることもサポートし、Chromeはbreak-after: column
をサポートし、 -webkit-column-break-after: always
もサポートします。
Firefoxは、ボックスの後のブレークを強制または許可するためのブレークbreak-after
またはプレフィックス付きプロパティのいずれもサポートしていません。
したがって、Edge以外では、ボックスの後の中断を実際に回避することはできません。 それらを強制したい場合は、次のCSSを使用して一部のブラウザーで結果を取得します。
.box { -webkit-break-after: always; break-after: column; }
ブラウザから印刷する場合のサポート
デスクトップブラウザから直接印刷する場合でも、ヘッドレスChromeを使用してPDFファイルを生成する場合でも、ブラウザテクノロジに依存するその他のソリューションを使用する場合でも、違いはありません。 フラグメンテーションプロパティのブラウザサポートに依存しています。
印刷スタイルシートを作成すると、multicolの場合と同様のbreakプロパティのサポートが見つかります。 ただし、古いブラウザをサポートするには、プロパティを2倍にして、 page-
プレフィックス付きのプロパティを使用する必要があります。
スタイルシートを印刷break-inside
最近のブラウザでは、 break-inside
プロパティを使用してボックス内の破損を防ぎ、 page-break-inside
プロパティを追加して古いブラウザのサポートを追加できます。
.box { page-break-inside: avoid; break-inside: avoid; }
スタイルシートとbreak-before
ビフォアを印刷する
ボックスの前に強制的に分割するには、 break-before:page
とpage-break-before: always
使用します。
.box { page-break-before: always; break-before: page; }
ボックスの前の分割を回避するには、 break-before: avoid-page
とpage-break-before: avoid
使用します。
.box { page-break-before: avoid; break-before: avoid-page; }
同等のマルチ列値で見られるよりも、ページ値とavoid-page
page
のサポートが優れています。 最新のブラウザの大部分はサポートされています。
スタイルシートとbreak-before
ビフォアを印刷する
ボックスの後に強制的に分割するには、 break-after: page
とpage-break-after: always
使用します。
.box { page-break-after: always; break-after: page; }
ボックス後の分割を防ぐには、 break-after: avoid-page
とpage-break-after: avoid
使用します。
.box { page-break-after: avoid; break-after: avoid-page; }
未亡人と孤児
widows
とorphans
のプロパティは、優れたクロスブラウザサポートを享受しています。Firefoxが実装されていない唯一のブラウザです。 マルチ列レイアウトまたは印刷スタイルシートを作成するときにこれらを使用することをお勧めします。 何らかの理由で機能しない場合は、未亡人や孤児が発生します。これは理想的ではありませんが、災害でもありません。 それらが機能する場合、あなたのタイポグラフィはそれのためにさらに良く見えるでしょう。
ボックス-装飾-休憩
box-decoration-break
の最後のプロパティは、Firefoxでのmulticolとprintをサポートしています。 Safari、Chrome、およびその他のChromiumベースのブラウザは、 -webkit-box-decoration-break
サポートしていますが、インライン要素でのみサポートされています。 たとえば、文の境界線の丸い線を複製できます。 彼らは私たちが見ている文脈ではサポートを持っていません。
以下のCodePenでは、 -webkit-box-decoration-break: clone
はtrueを返します。 ただし、このプロパティは、マルチ列コンテキストのボックスの境界には影響しません。
フラグメンテーションの使用
ご覧のとおり、ブラウザの断片化の現在の状態はやや断片化されています。 とは言うものの、達成できる合理的な量があり、それが失敗した場合、結果は最適ではない傾向がありますが、災害ではありません。 つまり、試してみる価値があります。
これらのプロパティを使いすぎると、期待したものとは異なる結果になる可能性があることに注意してください。 印刷せずにWebで作業していて、すべての段落の後に列の区切りを強制する場合、列のスペースよりも多くの段落になってしまうと、multicolはインライン方向にオーバーフローしてしまいます。 追加の段落を配置するための列が不足します。 したがって、サポートがある場合でも、慎重にテストする必要があります。多くの場合、少ないほど多いことを覚えておいてください。
その他のリソース
MDNに向かうプロパティの詳細を読むために、私は最近そこのページを更新し、ブラウザの互換性データを最新の状態に保とうとしています。 CSS Fragmentationのメインページは、個々のプロパティページにリンクしています。このページには、その他の例、ブラウザの互換性データ、およびこれらのプロパティの使用に関するその他の情報があります。