Briser les boîtes avec la fragmentation CSS

Publié: 2022-03-10
Résumé rapide ↬ Rachel Andrew a fouillé dans la spécification CSS Fragmentation, et la prise en charge du navigateur est quelque peu fragmentée. Dans cet article, elle explique ce qu'est la fragmentation, pourquoi vous voudrez peut-être l'utiliser et quel est l'état de la prise en charge des navigateurs.

Dans cet article, je vais vous présenter la spécification CSS Fragmentation. Vous n'en avez peut-être jamais entendu parler, cependant, si vous avez déjà créé une feuille de style d'impression et que vous vouliez contrôler où le contenu se brise entre les pages, ou la mise en page multi-colonnes et que vous vouliez empêcher un chiffre de se casser entre les colonnes, vous l'avez rencontré.

Je trouve que très souvent les problèmes que les gens signalent avec multicol sont vraiment des problèmes avec la prise en charge de la fragmentation par le navigateur. Après un bref aperçu des propriétés contenues dans cette spécification, j'expliquerai l'état actuel de la prise en charge des navigateurs et certaines des choses que vous pouvez faire pour qu'il fonctionne aussi bien que possible dans vos projets multicol et print.

Qu'est-ce que la fragmentation ?

La fragmentation en CSS décrit le processus par lequel le contenu est divisé en différentes boîtes. Actuellement, nous avons deux endroits où nous pourrions rencontrer une fragmentation sur le Web : lorsque nous imprimons un document et si nous utilisons une mise en page multi-colonnes. Ces deux choses sont essentiellement les mêmes. Lorsque vous imprimez (ou enregistrez au format PDF) une page Web, le contenu est fragmenté en autant de pages que nécessaire pour imprimer votre contenu.

Lorsque vous utilisez multicol, le contenu est fragmenté en colonnes. Chaque boîte de colonne est comme une page dans le contexte paginé. Si vous pensez qu'un ensemble de colonnes ressemble beaucoup à un ensemble de pages, cela peut être un moyen utile de penser au multicol et à la manière dont la fragmentation y fonctionne.

Si vous jetez un coup d'œil à la spécification de fragmentation CSS, vous verrez un troisième contexte fragmenté mentionné - ce contexte est les régions. Comme il n'existe actuellement aucune implémentation utilisable des régions, nous n'en traiterons pas dans cet article, mais nous examinerons plutôt les deux contextes que vous pourriez rencontrer dans votre travail.

Plus après saut! Continuez à lire ci-dessous ↓

Blocs et boîtes en ligne

Je vais beaucoup mentionner les boîtes de blocs dans cet article. Chaque élément de votre page a une boîte. Certaines de ces cases sont disposées sous forme de blocs : paragraphes, éléments de liste, en-têtes. Ceux-ci sont dits participer à un contexte de formatage de blocs. D'autres sont en ligne, comme les mots d'un paragraphe, les étendues et les éléments d'ancrage. Ceux-ci participent à un contexte de formatage en ligne. En termes simples, lorsque je fais référence à une boîte de bloc, je parle de boîtes autour de choses comme des paragraphes. Lorsqu'il s'agit de fragmentation, il est important de savoir à quel type de boîte vous avez affaire.

Pour plus d'informations sur la mise en page en bloc et en ligne, consultez l'article MDN "Mise en page en bloc et en ligne dans un flux normal". C'est l'une de ces choses que nous comprenons probablement tous à un certain niveau, mais que nous n'avons peut-être pas rencontrées auparavant.

Contrôler les pauses

Que vous créiez une feuille de style d'impression, que vous utilisiez un agent utilisateur d'impression spécifique pour créer un PDF ou que vous utilisiez multicol, vous rencontrerez parfois des problèmes qui ressemblent à ceci.

Dans l'exemple multicol ci-dessous, j'ai du contenu que j'affiche en trois colonnes. Au milieu du contenu se trouve une zone encadrée, qui est divisée en deux colonnes. Je ne veux pas de ce comportement — je voudrais que la boîte reste ensemble.

Trois colonnes avec une zone encadrée répartie sur deux d'entre elles
La boîte se divise en deux colonnes ( Grand aperçu )

Pour résoudre ce problème, j'ajoute la propriété break-inside: avoid à la case. La propriété break-inside contrôle les ruptures à l'intérieur des éléments lorsqu'ils se trouvent dans un contexte fragmenté. Dans un navigateur qui prend en charge cette propriété, la boîte restera désormais dans l'une des colonnes. Les colonnes auront l'air moins bien équilibrées, cependant, c'est généralement une meilleure chose que de se retrouver avec la boîte répartie sur plusieurs colonnes.

Voir l'exemple d'effraction Pen Simple par (Rachel Andrew.

Voir l'exemple d'effraction Pen Simple par (Rachel Andrew.

La propriété d' break-inside est l'une des propriétés détaillées dans la spécification de fragmentation. La liste complète des propriétés est la suivante :

  • break-before
  • break-after
  • break-inside
  • orphans
  • widows
  • box-decoration-break

Voyons comment ils sont censés fonctionner avant de passer à ce qui se passe réellement dans les navigateurs.

Les propriétés d' break-before et break-after

Il existe deux propriétés qui contrôlent les sauts entre les boîtes de niveau bloc : break-before et break-after . Si vous avez un h2 suivi de deux paragraphes <p> vous avez trois blocs de blocs et vous utiliserez ces propriétés pour contrôler les sauts entre le titre et le premier paragraphe, ou entre les deux paragraphes.

Les propriétés sont utilisées sur les sélecteurs qui ciblent l'élément que vous voulez casser avant ou après.

Par exemple, vous voudrez peut-être que votre feuille de style d'impression apparaisse sur une nouvelle page chaque fois qu'il y a un titre de niveau 2. Dans ce cas, vous utiliseriez break-before: page sur l'élément h2 . Cela contrôle la fragmentation et garantit qu'il y a toujours une pause avant la boîte de l'élément h2 .

 h2 { break-before: page; }

Une autre exigence courante consiste à éviter que les en-têtes ne se retrouvent en dernier sur une page ou une colonne. Dans ce cas, vous pouvez utiliser break-after avec une valeur d' avoid . Cela devrait éviter une rupture directement après la case de l'élément :

 h1, h2, h3, h4 { break-after: avoid; }

Fragments dans des fragments

Il est possible que vous ayez un élément fragmenté imbriqué dans un autre. Par exemple, avoir un multicol à l'intérieur de quelque chose qui est paginé. Dans ce cas, vous souhaiterez peut-être contrôler les sauts de page mais pas les colonnes, ou inversement. C'est pourquoi nous avons des valeurs telles que page qui forceraient toujours une pause avant ou après l'élément mais uniquement lorsque le fragment est une page. Ou avoid-page qui éviterait une pause avant ou après l'élément uniquement pour les contextes paginés.

Il en va de même pour les colonnes. Si vous utilisez la valeur column , cela forcerait toujours une pause avant ou après cet élément, mais uniquement pour les contextes multicol. La valeur avoid-column empêcherait une rupture dans les contextes multicol.

Il y a always une valeur dans la spécification de niveau 4 qui indique que vous voulez tout parcourir — page ou colonne. Cependant, en tant qu'ajout récent à la spécification, il ne nous est actuellement pas utile.

Valeurs supplémentaires pour les médias paginés

Si vous créez un livre ou un magazine, vous avez des pages de gauche et de droite. Vous voudrez peut-être contrôler la rupture afin de forcer quelque chose sur la page gauche ou droite d'une double page. Par conséquent, l'utilisation de ce qui suit insérerait un ou deux sauts de page avant le h2 pour s'assurer qu'il a été formaté comme une bonne page.

 h2 { break-before: right; }

Il existe également des valeurs recto et verso qui se rapportent à la progression des pages, car les livres écrits dans une langue verticale ou de droite à gauche ont une progression de page différente de celle des livres écrits en anglais. Je ne vais pas couvrir ces valeurs plus loin dans cet article car je suis principalement concerné par ce qui est possible à partir du navigateur cette fois.

break-inside

Nous avons déjà vu un exemple de propriété break-inside . Cette propriété contrôle la rupture à l' intérieur des blocs de blocs, par exemple à l'intérieur d'un paragraphe, d'un titre ou d'un div.

Les choses que vous ne voulez peut-être pas casser peuvent inclure un encadré comme décrit ci-dessus : des chiffres où vous ne voulez pas que la légende soit détachée de l'image, des tableaux, des listes, etc. Ajouter break-inside: avoid à tout conteneur que vous ne souhaitez pas casser dans un contexte de fragmentation. Si vous souhaitez uniquement éviter les ruptures entre les colonnes, utilisez break-inside: avoid-column et entre les pages break-inside: avoid-page .

Les propriétés des orphans et widows

Les propriétés des orphans et des widows traitent du nombre de lignes qui doivent être laissées avant ou après une pause (causée par une colonne ou une nouvelle page). Par exemple, si je veux éviter qu'une seule ligne soit laissée en fin de colonne, j'utiliserais la propriété orphans , comme en typographie, un orphelin est la première ligne d'un paragraphe qui apparaît seule en bas d'une page avec le reste du paragraphe divisé sur une autre page. La propriété doit être ajoutée au même élément qui se fragmente (dans notre cas, le conteneur multicol).

 .container { column-count: 3; orphans: 2; }

Pour contrôler le nombre de lignes devant figurer en haut d'une colonne ou d'une page après une pause, utilisez widows :

 .container { column-count: 3; widows: 2; }

Ces propriétés traitent des sauts entre les boîtes en ligne telles que les lignes de mots à l'intérieur d'un paragraphe. Par conséquent, ils n'aident pas dans la situation où un en-tête ou un autre élément de bloc est seul au bas d'une colonne ou d'une page, vous avez besoin des propriétés de rupture décrites ci-dessus pour cela.

Décoration de boîte

Une dernière propriété qui peut être intéressante est la propriété box-decoration-break . Cela contrôle la situation où vous avez une boîte avec une bordure brisée entre deux boîtes de colonnes ou pages. Voulez-vous que la bordure soit essentiellement coupée en deux ? Ou voulez-vous que chacune des deux moitiés de la boîte soit entièrement enveloppée dans une bordure ?

Le premier scénario est la valeur par défaut, et c'est comme si vous définissiez la propriété box-decoration-break sur slice sur la boîte.

 .box { box-decoration-break: slice; } 
Une boîte avec une bordure brisée entre les colonnes
Une valeur de tranche signifie que la bordure est effectivement coupée en deux ( Grand aperçu )

Pour obtenir le deuxième comportement, définissez box-decoration-break sur clone.

 .box { box-decoration-break: clone; } 
Les boîtes sont complètement emballées dans des bordures
Une valeur de clone signifie que la bordure est entièrement enveloppée autour de chaque fragment de la boîte ( Grand aperçu )

Prise en charge du navigateur pour la fragmentation

Nous arrivons maintenant à la raison pour laquelle je n'ai pas un tas d'exemples de CodePen ci-dessus pour vous montrer tout cela, et la principale raison pour laquelle j'écris cet article. La prise en charge du navigateur pour ces propriétés n'est pas excellente.

Si vous travaillez dans Paged Media avec un agent utilisateur spécifique tel que Prince, vous pouvez bénéficier d'un très bon support pour la fragmentation et vous trouverez probablement ces propriétés très utiles. Si vous travaillez avec un navigateur Web, soit en multicol, soit en créant des feuilles de style d'impression, soit en utilisant quelque chose comme Headless Chrome pour générer des PDF, la prise en charge est quelque peu inégale. Vous constaterez que le navigateur avec le meilleur support est Edge - jusqu'à ce qu'il passe de toute façon à Chromium !

Puis-je utiliser n'est pas trop utile pour expliquer la prise en charge en raison du mélange des propriétés de fragmentation avec multicol, puis de la présence de données distinctes pour les propriétés héritées. Ainsi, dans le cadre du travail que j'ai effectué pour MDN pour documenter les propriétés et leur prise en charge, j'ai commencé à tester la prise en charge réelle du navigateur. Voici quelques conseils basés sur ces tests.

Propriétés héritées et préfixées du fournisseur

Je ne peux pas aller beaucoup plus loin sans une leçon d'histoire. Si vous trouvez que vous avez vraiment besoin d'un support pour la fragmentation, vous pouvez trouver un certain soulagement dans les propriétés héritées qui faisaient à l'origine partie de CSS2 (ou dans certaines propriétés préfixées qui existent).

En CSS2, il y avait des propriétés pour contrôler le saut de page. Multicol n'existait pas à ce moment-là, donc le seul contexte fragmenté était un contexte paginé. Cela signifie que trois propriétés de saut de page spécifiques ont été introduites :

  • page-break-before
  • page-break-after
  • page-break-inside

Celles-ci fonctionnent de la même manière que les propriétés plus génériques sans le page- de page, contrôlant les sauts avant, après et à l'intérieur des boîtes. Pour les feuilles de style d'impression, vous constaterez que certains navigateurs plus anciens qui ne prennent pas en charge les nouvelles propriétés break- prennent en charge ces propriétés préfixées de page. Les propriétés sont traitées comme des alias pour les nouvelles propriétés.

Dans un brouillon de travail de 2005 de la spécification multicol, vous trouverez des détails sur les propriétés de rupture pour multicol - en utilisant des propriétés préfixées par column- (c'est-à-dire column-break-before , column-break-after et column-break-inside ). En 2009, ceux-ci avaient disparu et un brouillon figurait dans la spécification multicol pour les propriétés de rupture sans préfixe qui ont finalement fait leur chemin dans la spécification CSS Fragmentation.

Cependant, certaines propriétés spécifiques aux colonnes préfixées par le fournisseur ont été implémentées en fonction de ces propriétés. Ceux-ci sont:

  • -webkit-column-break-before
  • -webkit-column-break-after
  • -webkit-column-break-inside

Prise en charge de la fragmentation dans Multicol

Ce qui suit est basé sur le test de ces fonctionnalités dans des contextes multicol. J'ai essayé d'expliquer ce qui est possible, mais jetez un œil aux CodePens dans les navigateurs dont vous disposez.

Multicol Et break-inside

La prise en charge de multicol est la meilleure pour la propriété break-inside . Les versions à jour de Chrome, Firefox, Edge et Safari prennent toutes en charge break-inside: avoid . Vous devriez donc constater que vous pouvez empêcher les boîtes de se casser entre les colonnes lors de l'utilisation de multicol.

Plusieurs navigateurs, à l'exception de Firefox, prennent en charge la propriété -webkit-column-break-inside , cela peut être utilisé avec une valeur d' avoid et peut empêcher les boîtes de se casser entre les colonnes qui ne prennent pas en charge break-inside .

Firefox prend en charge page-break-inside: avoid en multicol. Par conséquent, l'utilisation de cette propriété empêchera les ruptures à l'intérieur des boîtes dans les navigateurs Firefox antérieurs à Firefox 65.

Cela signifie que si vous souhaitez éviter les ruptures entre les cases en multicol, l'utilisation du CSS suivant couvrira autant de navigateurs que possible, en remontant le plus loin possible.

 .box { -webkit-column-break-inside: avoid; page-break-inside: avoid; break-inside: avoid; }

En ce qui concerne la valeur de la column , indiquer explicitement que vous souhaitez uniquement éviter les ruptures entre les colonnes, et non les pages, fonctionne dans tous les navigateurs sauf Firefox.

Le CodePen ci-dessous résume certains de ces tests en multicol afin que vous puissiez les essayer par vous-même.

Voir le Pen Multicol Fragmentation Test: break-inside par Rachel Andrew.

Voir le Pen Multicol Fragmentation Test: break-inside par Rachel Andrew.

Multicol Et break-before

Afin d'éviter les sauts avant un élément, vous devriez pouvoir utiliser break-before: avoid ou break-before: avoid-column . La propriété éviter n'a pas de support de navigateur.

Edge prend en charge break-before: column pour toujours forcer une pause avant la case de l'élément.

Safari, Chrome et Edge prennent également en charge -webkit-column-break-before: always qui forcera une pause avant la case de l'élément. Par conséquent, si vous souhaitez forcer une pause avant la boîte d'un élément, vous devez utiliser :

 .box { -webkit-column-break-before: always; break-before: column; }

Empêcher une pause avant la boîte est actuellement une tâche impossible. Vous pouvez jouer avec quelques exemples de ces propriétés ci-dessous :

Voir le Pen Multicol Fragmentation Test: break-before par Rachel Andrew).

Voir le Pen Multicol Fragmentation Test: break-before par Rachel Andrew).

Multicol Et break-after

Pour éviter les ruptures après un élément, pour éviter qu'il ne devienne la dernière chose en bas d'une colonne, vous devriez pouvoir utiliser break-after: avoid et break-after: avoid-column . Le seul navigateur qui les prend en charge est Edge.

Edge prend également en charge les sauts forcés après un élément en utilisant break-after: column , Chrome prend en charge break-after: column et également -webkit-column-break-after: always .

Firefox ne prend pas en charge break-after ou l'une des propriétés préfixées pour forcer ou autoriser les pauses après une boîte.

Par conséquent, à part Edge, vous ne pouvez pas vraiment éviter les pauses après une boîte. Si vous souhaitez les forcer, vous obtiendrez des résultats dans certains navigateurs en utilisant le CSS suivant :

 .box { -webkit-break-after: always; break-after: column; } 

Voir le Pen Multicol Fragmentation Test: break-after par Rachel Andrew).

Voir le Pen Multicol Fragmentation Test: break-after par Rachel Andrew).

Prise en charge lors de l'impression à partir du navigateur

Que vous imprimiez directement à partir de votre navigateur de bureau ou génériez des fichiers PDF à l'aide de Chrome sans tête ou d'une autre solution reposant sur la technologie du navigateur, cela ne fait aucune différence. Vous dépendez de la prise en charge du navigateur pour les propriétés de fragmentation.

Si vous créez une feuille de style d'impression, vous trouverez un support similaire pour les propriétés break comme pour multicol ; cependant, pour prendre en charge les navigateurs plus anciens, vous devez doubler les propriétés pour utiliser les propriétés de préfixe de page- .

Feuilles de style break-inside

Dans les navigateurs modernes, la propriété break-inside peut être utilisée pour empêcher les ruptures à l'intérieur des boîtes, ajoutez la propriété page-break-inside pour ajouter la prise en charge des anciens navigateurs.

 .box { page-break-inside: avoid; break-inside: avoid; }

Feuilles de style d'impression et break-before

Pour forcer les sauts avant une boîte, utilisez break-before:page avec page-break-before: always .

 .box { page-break-before: always; break-before: page; }

Pour éviter les sauts avant une boîte, utilisez break-before: avoid-page avec page-break-before: avoid .

 .box { page-break-before: avoid; break-before: avoid-page; }

Il existe une meilleure prise en charge des valeurs de page et avoid-page que ce que nous voyons pour les valeurs multicol équivalentes. La majorité des navigateurs modernes sont pris en charge.

Feuilles de style d'impression et break-before

Pour forcer les sauts après une boîte, utilisez break-after: page avec page-break-after: always .

 .box { page-break-after: always; break-after: page; }

Pour éviter les sauts après une boîte, utilisez break-after: avoid-page avec page-break-after: avoid .

 .box { page-break-after: avoid; break-after: avoid-page; }

Veuves et orphelins

Les propriétés widows et orphans bénéficient d'un bon support multi-navigateurs - le seul navigateur sans implémentation étant Firefox. Je suggérerais de les utiliser lors de la création d'une mise en page multicol ou d'une feuille de style d'impression. S'ils ne fonctionnent pas pour une raison quelconque, vous aurez des veuves et des orphelins, ce qui n'est pas idéal mais n'est pas non plus un désastre. S'ils fonctionnent, votre typographie n'en sera que meilleure.

box-déco-pause

La dernière propriété de box-decoration-break prend en charge le multicol et l'impression dans Firefox. Safari, Chrome et d'autres navigateurs basés sur Chromium prennent en charge -webkit-box-decoration-break , mais uniquement sur les éléments en ligne. Ainsi, vous pouvez cloner les bordures autour des lignes d'une phrase par exemple ; ils n'ont pas de soutien dans le contexte que nous examinons.

Dans le CodePen ci-dessous, vous pouvez voir que le test de -webkit-box-decoration-break: clone with Feature Queries renvoie true ; cependant, la propriété n'a aucun effet sur la bordure de la boîte dans le contexte multicol.

Voir le Pen Multicol : coffret-déco-pause par Rachel Andrew.

Voir le Pen Multicol : coffret-déco-pause par Rachel Andrew.

Utilisation de la fragmentation

Comme vous pouvez le voir, l'état actuel de la fragmentation dans les navigateurs est quelque peu fragmenté ! Cela dit, vous pouvez atteindre un montant raisonnable et en cas d'échec, le résultat a tendance à être sous-optimal mais pas catastrophique. Ce qui signifie que cela vaut la peine d'essayer.

Il convient de noter qu'être trop lourd avec ces propriétés pourrait entraîner autre chose que ce que vous espériez. Si vous travaillez sur le Web plutôt que d'imprimer et de forcer les sauts de colonne après chaque paragraphe, puis que vous vous retrouvez avec plus de paragraphes que d'espace pour les colonnes, le multicol finira par déborder dans la direction en ligne. Il manquera de colonnes pour placer vos paragraphes supplémentaires. Par conséquent, même là où il y a un support, vous devez toujours tester soigneusement et rappelez-vous que moins c'est plus dans de nombreux cas.

Davantage de ressources

Pour en savoir plus sur les propriétés, rendez-vous sur MDN, j'ai récemment mis à jour les pages et j'essaie également de maintenir à jour les données de compatibilité du navigateur. La page principale de CSS Fragmentation renvoie aux pages de propriétés individuelles qui contiennent d'autres exemples, des données de compatibilité de navigateur et d'autres informations sur l'utilisation de ces propriétés.