Romper cajas con fragmentación de CSS
Publicado: 2022-03-10En este artículo, les presentaré la especificación de fragmentación de CSS. Es posible que nunca haya oído hablar de él, sin embargo, si alguna vez creó una hoja de estilo de impresión y deseaba controlar dónde se divide el contenido entre páginas, o un diseño de varias columnas y deseaba evitar que una figura se dividiera entre columnas, lo ha encontrado.
Encuentro que muy a menudo los problemas que las personas informan con multicol son realmente problemas con el soporte de fragmentación del navegador. Después de un resumen rápido de las propiedades contenidas en esta especificación, explicaré el estado actual del soporte del navegador y algunas de las cosas que puede hacer para que funcione tan bien como pueda en sus proyectos multicol y de impresión.
¿Qué es la fragmentación?
La fragmentación en CSS describe el proceso por el cual el contenido se divide en diferentes cuadros. Actualmente, tenemos dos lugares en los que podemos encontrarnos con la fragmentación en la web: cuando imprimimos un documento y si usamos el diseño de varias columnas. Estas dos cosas son esencialmente lo mismo. Cuando imprime (o guarda en PDF) una página web, el contenido se fragmenta en tantas páginas como sea necesario para imprimir su contenido.
Cuando usa multicol, el contenido se fragmenta en columnas. Cada cuadro de columna es como una página en el contexto paginado. Si piensa que un conjunto de columnas es muy parecido a un conjunto de páginas, puede ser una forma útil de pensar en multicol y cómo funciona la fragmentación en él.
Si observa la Especificación de fragmentación de CSS, verá un tercer contexto fragmentado mencionado: ese contexto es Regiones. Como no hay implementaciones utilizables actuales de Regions, no nos ocuparemos de eso en este artículo, sino que veremos los dos contextos con los que puede encontrarse en su trabajo.
Cajas en bloque y en línea
Voy a mencionar mucho las cajas de bloques en este artículo. Cada elemento de su página tiene una caja. Algunos de esos cuadros están dispuestos como bloques: párrafos, elementos de lista, encabezados. Se dice que estos participan en un contexto de formato de bloque. Otros están en línea, como las palabras en un párrafo, los tramos y los elementos de anclaje. Estos participan en un contexto de formato en línea. En pocas palabras, cuando me refiero a un cuadro de bloque, me refiero a cuadros alrededor de cosas como párrafos. Cuando se trata de fragmentación, es importante saber con qué tipo de caja se trata.
Para obtener más información sobre el diseño en bloque y en línea, consulte el artículo de MDN "Diseño en bloque y en línea en flujo normal". Es una de esas cosas que probablemente todos entendemos en algún nivel, pero es posible que no hayamos encontrado la terminología de antes.
Control de pausas
Ya sea que esté creando una hoja de estilo de impresión, usando un agente de usuario de impresión específico para hacer un PDF o usando multicol, a veces se encontrará con problemas que se parecen a este.
En el siguiente ejemplo multicolor, tengo algo de contenido que estoy mostrando en tres columnas. En el medio del contenido hay un área encuadrada, que se divide en dos columnas. No quiero este comportamiento, me gustaría que la caja permaneciera unida.
Para arreglar esto, agrego la propiedad break-inside: avoid
al cuadro. Los controles de propiedad break-inside
rompen dentro de los elementos cuando están en un contexto fragmentado. En un navegador que admita esta propiedad, el cuadro permanecerá ahora en una de las columnas. Las columnas se verán menos equilibradas, sin embargo, eso generalmente es mejor que terminar con el cuadro dividido en columnas.
La propiedad break-inside
es una de las propiedades detalladas en la especificación de fragmentación. La lista completa de propiedades es la siguiente:
-
break-before
-
break-after
-
break-inside
-
orphans
-
widows
-
box-decoration-break
Echemos un vistazo a cómo se supone que funcionan antes de pasar a lo que realmente sucede en los navegadores.
Las propiedades break-before
y break-after
Hay dos propiedades que controlan las rupturas entre los cuadros a nivel de bloque: break-before
y break-after
. Si tiene un h2
seguido de dos párrafos <p>
, tiene tres cuadros de bloque y usaría estas propiedades para controlar los saltos entre el encabezado y el primer párrafo, o entre los dos párrafos.
Las propiedades se usan en selectores que apuntan al elemento que desea romper antes o después.
Por ejemplo, es posible que desee que su hoja de estilo de impresión se divida en una nueva página cada vez que haya un encabezado de nivel 2. En este caso, usaría break-before: page
en el elemento h2
. Esto controla la fragmentación y asegura que siempre haya una ruptura antes de la caja del elemento h2
.
h2 { break-before: page; }
Otro requisito común es evitar que los encabezados terminen como lo último en una página o columna. En este caso, puede usar break-after
con un valor de avoid
. Esto debería evitar una ruptura directamente después del cuadro del elemento:
h1, h2, h3, h4 { break-after: avoid; }
Fragmentos dentro de fragmentos
Es posible que tengas un elemento fragmentado anidado dentro de otro. Por ejemplo, tener un multicol dentro de algo que está paginado. En ese caso, es posible que desee controlar los saltos para las páginas pero no para las columnas, o al revés. Esta es la razón por la que tenemos valores como page
que siempre forzarían una ruptura antes o después del elemento, pero solo cuando el fragmento es una página. O avoid-page
que evitaría una ruptura antes o después del elemento solo para contextos paginados.
Lo mismo se aplica a las columnas. Si usa la column
de valor, esto siempre forzaría una ruptura antes o después de ese elemento, pero solo para contextos multicol. El valor avoid-column
evitaría una ruptura en contextos multicolumna.
Hay un valor always
en la especificación de Nivel 4 que indica que desea analizar todo: página o columna. Sin embargo, como una adición reciente a la especificación, actualmente no es útil para nosotros.
Valores adicionales para medios paginados
Si está creando un libro o una revista, tiene páginas izquierda y derecha. Es posible que desee controlar la división para forzar algo en la página izquierda o derecha de un pliego. Por lo tanto, usar lo siguiente insertaría uno o dos saltos de página antes de h2
para garantizar que se formateó como una página correcta.
h2 { break-before: right; }
También hay valores de recto y verso que se relacionan con la progresión de la página, ya que los libros escritos en un idioma vertical o de derecha a izquierda tienen una progresión de página diferente a la de los libros escritos en inglés. No voy a cubrir más estos valores en este artículo, ya que esta vez me preocupa principalmente lo que es posible desde el navegador.
break-inside
Ya hemos visto un ejemplo de la propiedad break-inside
. Esta propiedad controla la ruptura dentro de los cuadros de bloque, por ejemplo, dentro de un párrafo, encabezado o div.
Las cosas que quizás no desee romper pueden incluir un recuadro como se describe anteriormente: figuras en las que no desea que el título se separe de la imagen, tablas, listas, etc. Agregue break-inside: avoid
cualquier contenedor que no desee romper en ningún contexto de fragmentación. Si solo desea evitar las rupturas entre columnas, use break-inside: avoid-column
y entre páginas break-inside: avoid-page
.
Las propiedades de los orphans
y widows
Las propiedades de orphans
y widows
se ocupan de cuántas líneas deben quedar antes o después de un salto (ya sea causado por una columna o una nueva página). Por ejemplo, si quiero evitar que quede una sola línea al final de una columna, usaría la propiedad de orphans
, como en tipografía, un huérfano es la primera línea de un párrafo que aparece sola al final de una página con el resto del párrafo dividido en otra página. La propiedad debe agregarse al mismo elemento que se está fragmentando (en nuestro caso, el contenedor multicol).
.container { column-count: 3; orphans: 2; }
Para controlar cuántas líneas debe haber en la parte superior de una columna o página después de un salto, use widows
:
.container { column-count: 3; widows: 2; }
Estas propiedades se ocupan de los saltos entre cuadros en línea, como las líneas de palabras dentro de un párrafo. Por lo tanto, no ayudan en la situación en la que un encabezado u otro elemento de bloque está solo en la parte inferior de una columna o página, necesita las propiedades de ruptura discutidas anteriormente para eso.
Decoración de caja
Una propiedad final que puede ser de interés es la propiedad box-decoration-break
. Esto controla la situación en la que tiene un cuadro con un borde roto entre dos cuadros de columna o páginas. ¿Quiere que el borde se corte esencialmente por la mitad? ¿O quieres que cada una de las dos mitades de la caja esté completamente envuelta en un borde?
El primer escenario es el predeterminado, y es como si configurara la propiedad box-decoration-break
para slice
en el cuadro.
.box { box-decoration-break: slice; }
Para obtener el segundo comportamiento, establezca box-decoration-break
en clon.
.box { box-decoration-break: clone; }
Soporte de navegador para fragmentación
Ahora llegamos a la razón por la que no tengo un montón de ejemplos de CodePen arriba para demostrarle todo esto, y la razón principal por la que escribí este artículo. El soporte del navegador para estas propiedades no es muy bueno.
Si está trabajando en Paged Media con un agente de usuario específico como Prince, entonces puede disfrutar de un muy buen soporte para la fragmentación, y probablemente encontrará estas propiedades muy útiles. Si está trabajando con un navegador web, ya sea en multicol, creando hojas de estilo de impresión o usando algo como Headless Chrome para generar archivos PDF, el soporte es algo irregular. Descubrirá que el navegador con la mejor compatibilidad es Edge, ¡hasta que se cambie a Chromium de todos modos!
Can I Use no es demasiado útil para explicar el soporte debido a la combinación de las propiedades de fragmentación con multicol y luego tener algunos datos separados para las propiedades heredadas. Entonces, como parte del trabajo que he estado haciendo para MDN para documentar las propiedades y su compatibilidad, comencé a probar la compatibilidad real del navegador. Lo que sigue es un consejo basado en esa prueba.
Propiedades prefijadas heredadas y de proveedor
No puedo ir mucho más lejos sin una lección de historia. Si encuentra que realmente necesita soporte para la fragmentación, entonces puede encontrar algo de alivio en las propiedades heredadas que originalmente formaban parte de CSS2 (o en algunas propiedades prefijadas que existen).
En CSS2, había propiedades para controlar los saltos de página. Multicol no existía en ese momento, por lo que el único contexto fragmentado era uno paginado. Esto significó que se introdujeron tres propiedades de salto de página específicas:
-
page-break-before
-
page-break-after
-
page-break-inside
Estos funcionan de manera similar a las propiedades más genéricas sin el page-
de página, controlando las pausas antes, después y dentro de los cuadros. Para las hojas de estilo de impresión, encontrará que algunos navegadores antiguos que no son compatibles con las nuevas propiedades de break-
, sí son compatibles con estas propiedades de prefijo de página. Las propiedades se tratan como alias para las nuevas propiedades.
En un borrador de trabajo de 2005 de la especificación multicol hay detalles de las propiedades de división para multicol, utilizando propiedades con el prefijo column-
(es decir column-break-before
, column-break-after
y column-break-inside
). Para 2009, estos habían desaparecido, y había un borrador en la especificación multicol para propiedades de ruptura sin prefijo que finalmente se abrió paso en la especificación de fragmentación CSS.
Sin embargo, algunas propiedades específicas de columna con prefijo de proveedor se implementaron en función de estas propiedades. Estos son:
-
-webkit-column-break-before
-
-webkit-column-break-after
-
-webkit-column-break-inside
Soporte para fragmentación en Multicol
Lo siguiente se basa en probar estas características en contextos multicol. He tratado de explicar lo que es posible, pero eche un vistazo a CodePens en cualquier navegador que tenga disponible.
Multicol y break-inside
El soporte en multicol es mejor para la propiedad break-inside
. Las versiones actualizadas de Chrome, Firefox, Edge y Safari son compatibles break-inside: avoid
. Por lo tanto, debería encontrar que puede evitar que los cuadros se rompan entre columnas cuando usa multicol.
Varios navegadores, con la excepción de Firefox, admiten la -webkit-column-break-inside
, que se puede usar con un valor de avoid
y puede evitar que los cuadros se rompan entre columnas que no tienen soporte para break-inside
.
Firefox admite saltos page-break-inside: avoid
en multicol. Por lo tanto, el uso de esta propiedad evitará interrupciones dentro de los cuadros en los navegadores Firefox anteriores a Firefox 65.
Esto significa que si desea evitar interrupciones entre cuadros en multicol, el uso del siguiente CSS cubrirá tantos navegadores como sea posible, retrocediendo tanto como sea posible.
.box { -webkit-column-break-inside: avoid; page-break-inside: avoid; break-inside: avoid; }
En cuanto al valor de la column
, indicar explícitamente que solo desea evitar las pausas entre las columnas y no entre las páginas funciona en todos los navegadores excepto en Firefox.
El CodePen a continuación resume algunas de estas pruebas en multicolor para que pueda probarlas usted mismo.
Multicol Y break-before
Para evitar interrupciones antes de un elemento, debe poder usar break-before: avoid
o break-before: avoid-column
. La propiedad de evitar no tiene soporte de navegador.
Edge admite break-before: column
para forzar siempre un descanso antes del cuadro del elemento.
Safari, Chrome y Edge también son compatibles -webkit-column-break-before: always
, lo que forzará un descanso antes del cuadro del elemento. Por lo tanto, si desea forzar un descanso antes de la caja de un elemento, debe usar:
.box { -webkit-column-break-before: always; break-before: column; }
Prevenir una rotura ante el box es actualmente una tarea imposible. Puedes jugar con algunos ejemplos de estas propiedades a continuación:
Multicol Y break-after
Para evitar saltos después de un elemento, para evitar que se convierta en lo último en la parte inferior de una columna, debe poder usar break-after: avoid
y break-after: avoid-column
. El único navegador con soporte para estos es Edge.
Edge también admite forzar saltos después de un elemento mediante break-after: column
, Chrome admite break-after: column
y también -webkit-column-break-after: always
.
Firefox no es compatible break-after
ni con ninguna de las propiedades prefijadas para forzar o permitir pausas posteriores a un cuadro.
Por lo tanto, aparte de Edge, realmente no puedes evitar los descansos después de una caja. Si quieres forzarlas, obtendrás resultados en algunos navegadores utilizando el siguiente CSS:
.box { -webkit-break-after: always; break-after: column; }
Soporte al imprimir desde el navegador
Ya sea que imprima directamente desde su navegador de escritorio o genere archivos PDF usando Chrome sin interfaz gráfica o alguna otra solución que dependa de la tecnología del navegador, no hace ninguna diferencia. Depende de la compatibilidad del navegador con las propiedades de fragmentación.
Si crea una hoja de estilo de impresión, encontrará un soporte similar para las propiedades de ruptura que para multicol; sin embargo, para admitir navegadores más antiguos, debe duplicar las propiedades para usar las page-
con prefijo de página.
Imprimir hojas de estilo y break-inside
En los navegadores modernos, la propiedad break-inside
se puede usar para evitar saltos dentro de los cuadros, agregue la propiedad page-break-inside
para agregar soporte para navegadores más antiguos.
.box { page-break-inside: avoid; break-inside: avoid; }
Imprimir hojas de estilo y break-before
Para forzar saltos antes de un cuadro, use break-before:page
junto con page-break-before: always
.
.box { page-break-before: always; break-before: page; }
Para evitar saltos antes de un cuadro, use break-before: avoid-page
junto con page-break-before: avoid
.
.box { page-break-before: avoid; break-before: avoid-page; }
Hay un mejor soporte para los valores de page
y avoid-page
de lo que vemos para los valores multicol equivalentes. La mayoría de los navegadores modernos tienen soporte.
Imprimir hojas de estilo y break-before
Para forzar saltos después de un cuadro, use break-after: page
junto con page-break-after: always
.
.box { page-break-after: always; break-after: page; }
Para evitar saltos después de un cuadro, use break-after: avoid-page
junto con page-break-after: avoid
.
.box { page-break-after: avoid; break-after: avoid-page; }
viudas y huérfanos
Las propiedades widows
y orphans
disfrutan de un buen soporte entre navegadores: el único navegador sin implementación es Firefox. Sugeriría usarlos al crear un diseño multicolor o una hoja de estilo de impresión. Si no funcionan por alguna razón, tendrás viudas y huérfanos, lo cual no es lo ideal pero tampoco es un desastre. Si funcionan, su tipografía se verá mucho mejor.
caja-decoración-descanso
La propiedad final de box-decoration-break
tiene soporte para multicol e print en Firefox. Safari, Chrome y otros navegadores basados en Chromium admiten -webkit-box-decoration-break
, pero solo en elementos en línea. Entonces puede clonar bordes alrededor de líneas de una oración, por ejemplo; no tienen apoyo en el contexto que estamos viendo.
En el CodePen a continuación, puede ver que la prueba de -webkit-box-decoration-break: clone
con Feature Queries devuelve verdadero; sin embargo, la propiedad no tiene efecto en el borde del cuadro en el contexto multicolor.
Uso de fragmentación
Como puede ver, ¡el estado actual de fragmentación en los navegadores está algo fragmentado! Dicho esto, hay una cantidad razonable que puede lograr y donde falla, el resultado tiende a ser subóptimo pero no un desastre. Lo que significa que vale la pena intentarlo.
Vale la pena señalar que ser demasiado severo con estas propiedades podría resultar en algo diferente a lo que esperaba. Si está trabajando en la web en lugar de imprimir y forzar saltos de columna después de cada párrafo, termina con más párrafos que espacio para las columnas, multicol terminará desbordándose en la dirección en línea. Se quedará sin columnas para colocar sus párrafos adicionales. Por lo tanto, incluso cuando hay soporte, aún debe probar con cuidado y recordar que menos es más en muchos casos.
Más recursos
Para leer más sobre las propiedades, diríjase a MDN, recientemente actualicé las páginas allí y también estoy tratando de mantener actualizados los datos de compatibilidad del navegador. La página principal de Fragmentación de CSS enlaza con las páginas de propiedades individuales que tienen más ejemplos, datos de compatibilidad del navegador y otra información sobre el uso de estas propiedades.