Estilos Css para imprimir: La regla @page en los medios paginados

Un repaso a los documentos, reglas y propiedades Css para una correcta impresión de los documentos web.

Estilos Css para imprimir: La regla @page en los medios paginados

Por Kseso ✎ 20

Estar en una página y decidir imprimir un artículo y ver que entre sidebar, baners publicitarios, menús y otra basura te comen 4 páginas y que el contenido queda cortado dice mucho de esa página. Pero qué malo todo lo que dice.
Y todo por no tomarse un momento para hacer que la impresión de su web se realice correctamente.

Con Css se puede controlar también el qué y cómo se imprimen las webs. Para ello tiene todo un capítulo. Son los estilos para los medios paginados (Nota 1 ↓).

Actualización: El documento actual, en desarrollo, es CSS Paged Media Module Level 3. Lamentablemente su desarrollo e implementación de sus novedades en los navegadores no está siendo tan rápida como sería de desear.

Estilos Css para imprimir: La regla @page en los medios paginados
Crédito imagen: [1]

Css para imprimir

La llamada a los estilos de impresión se puede hacer de la misma manera que el de los de visión en pantalla. Si es mediante el <link... > sólo se necesita indicar el tipo de media:

<link href="impresion.css" type="text/css" media="print" />

También se pueden incluir en el head usando el elemento <style> y la manera de indicar que son estilos para la impresión es:

<style type="text/css"> @media print { /* Todas las reglas Css */ } <style>

El modelo de caja (boxmodel) de Page

Los media print generan una caja general donde alojar todos los contenidos. Esta caja se conoce como page.

El boxmodel por defecto en los medios impresos es el mismo que en el media="screen". El tamaño final de la caja generada page es la suma de sus (margin + border + padding) laterales + su width o height.

Además de este área general el nuevo docuento define 16 áreas o cajas de márgenes donde poder colocar contenido generado con CSS. Si estas cajas de márgenes quedan fuera del área de impresión generan una nueva página.

DPage-Margin Boxes y sus valore por defecto
Page-margin box text-align vertical-align
top-left-corner right middle
top-left left middle
top-center center middle
top-right right middle
top-right-corner left middle
left-top center top
left-middle center middle
left-bottom center bottom
right-top center top
right-middle center middle
right-bottom center bottom
bottom-left-corner right middle
bottom-left left middle
bottom-center center middle
bottom-right right middle
bottom-right-corner left middle

La regla @page

Se debe definir al inicio del CSS y es la que definirá los estilos de esta caja de contención. Para ellos se utiliza el selector @page.

En ella se pueden definir las propiedades específicas para el medio impreso. Entre otras:

  • Tamaños y orientación
  • los márgenes
  • las líneas viudas y huérfanas
  • los saltos de página

@page { /* declaraciones Css */ }

Esta regla admite también añadirle clases y según el último documento admite otras at-rules dentro de ella:

@page {size: portrait;} @page rotada {size: landscape;} table {page: rotada; page-break-before: right;} @page { /*declaraciones*/ @top-left { content: "Título"; } @top-right { content: "Pág. " counter(page); } }

Ten presente el área no imprimible: Es el área de una hoja en la que un dispositivo físico, como una impresora, no es capaz de imprimir, por lo general debido al mecanismo de la impresora. Este valor depende de la impresora y es generalmente una pequeña región a lo largo de cada borde de la hoja de papel.

Propiedades propias de @page

ilustración ornamental
Size:
Define el tamaño de la caja generada page. Se le pueden declarar valores absolutos: numéricos con su unidad correspondiente (20cm | 190mm etc) o con page-size (nombres estándares)
También podemos hacerlo con valores relativos (escalables, es decir, que se ajuste al tamaño de hoja disponibles): con el valor auto (que es el valor por defecto) o indicar su orientación: portrait | landscape
size: portrait;
Especifica que el contenido de la página se imprime en orientación vertical. Los lados más cortos de la caja de página son horizontales. Si page-size no se especifica, el tamaño de la hoja de la página es elegido por la impresora.
size: landscape;
Especifica que el contenido de la página se va a imprimir en orientación horizontal. Lo mismo para page-size omitido.
page-size
son nombres claves de tamaños de papel estándar como A3, A0, B5, legal, letter... en combinación con la orientación:

@page { size: A4 landscape; }

El tamaño de "page" será el de un A4 (210mmx297mm) puesto en horizontal. Así que si la impresora no puede llegar al borde del papel para imprimir debería salirte el mensaje de si escalar la impresión o no.
Márgenes de @page

@page { size: auto;/* es el valor por defecto */ margin: 10%; }

Recuerda que el % tiene como referente del cálculo a su ancestro, en este caso el folio de papel. Así que si la hoja de la impresora es un A4, por ejemplo, los márgenes serán de 21mm en los lados cortos y 29´7mm en los largos (medidos desde los bordes del papel) y "auto" significa lo mismo que en "media='screen'": todo el espacio restante.

Las pseudoclasses: :left :right :first :blank

Para controlar aspectos de algunas páginas claves como la primera o si son páginas a izquieda o a derecha (al encuadernar o en impresión a doble cara) Css para los medios paginados define estas tres pseudoclases para @page.
:first para la primera página.
:right para las páginas que serán encuadernadas a la derecha.
:left para las páginas que su posición será a la izquierda.
:blank selecciona las páginas sin contenido (en blanco) que se generan por los saltos de página.

@page :left { margin-left: 3cm; margin-right: 4cm; } @page :right { margin-left: 4cm; margin-right: 3cm; } @page :first { margin-top: 4cm; }

Saltos de página

ilustración ornamental

Para evitar que ciertos elementos se corten y repartan en 2 páginas se puede definir los saltos de página antes: page-break-before, después: page-break-after o dentro page-break-inside del elemento. Estos saltos de página sólo se pueden aplicar a elementos de bloque.
page-break-before y page-break-after no se heredan y permiten los valores:
auto: Ni fuerza ni prohibe un salto de página antes (después) de la caja generada.
always: Siempre fuerza un salto de página antes (después) de la caja generada.
avoid: Evita un salto de página antes (después) de la caja generada.
left: Fuerza uno o dos saltos de página antes (después) de la caja generada para que la siguiente página sea compuesta como una página izquierda.
right: Fuerza uno o dos saltos de página antes (después) de la caja generada para que la siguiente página sea compuesta como una página derecha.

page-break-inside: Sí se hereda. Define si se permiten o no saltos de línea dentro de la caja. Los valores permitidos son: auto, avoid, inherit

Las propiedades 'orphans' y 'widows'

La propiedad orphans (huérfanas) especifica el número mínimo de líneas de un párrafo que deben dejarse al final de una página. La propiedad widows (viudas) especifica el número mínimo de líneas de un párrafo que deben dejarse al comienzo de la página.

Supón, por ejemplo, que la hoja de estilo contiene orphans : 4 y widows : 2, y hay 20 líneas disponibles al final de la página actual:

  • Si un párrafo al final de la página actual contiene 20 líneas o menos, deber colocarse en la página actual.
  • Si el párrafo contiene 21 o 22 líneas, la segunda parte del párrafo no debe violar la restricción 'widows', y entonces la segunda parte debe contener exactamente dos líneas.
  • Si el párrafo contiene 23 líneas o más, la primer parte debe contener 20 líneas y la segunda parte las líneas restantes.

Ahora supón que orphans es '10', widows es '20', y hay '8' líneas disponibles al final de la página actual:

  • Si un párrafo al final de la página actual contiene 8 líneas o menos, debe colocarse en la página actual.
  • Si el párrafo contiene 9 líneas o más, no puede ser cortado (esto violaría la restricción impuesta a las líneas huérfanas), así que debe moverse como un bloque a la página siguiente.

Contadores y contenido generado con CSS

En los medios impresos también es posible generar contenido vía CSS además de con los pseudoelementos "tradicionales" con los Page-Margin Boxes mencionados antes. Y en conjunción con las pseudoclases :left :right :first :blank especificar en qué tipo de páginas generarlo.

@page:blank { @top-center { content: 'Esta es una página en blanco'; /*otras declaraciones*/ } }

De la misma forma se puedes usar estos page-margin boxes para mostrar cualquier contador CSS que se necesite utilizar. Como numerar las páginas a izquierdas a la izquierda y las a derechas a la derecha:

@page:left { @bottom-left { content: counter(pagina); } } @page:right { @bottom-right { content: counter(pagina); } }

Notas a pie de página

También es posible que cierto contenido sea movido al pie de la página y que se muestre como las típicas notas a pie de página. Esta particularidad está contemplada en el apartado footnotes del documento CSS Generated Content for Paged Media.

<p>Algo de texto... XXX <span class="nota_al_pie">yyy</span>... </p> @page { @footnote { float: bottom; } } span.nota_al_pie { float: footnote; }

Y por supuesto utilizar un contador específico para cada una de las notas a pie de página. Bien global o por página.

Ten presente

imagen ornamental
  • En los saltos de línea:
    • Los saltos de página no pueden producirse dentro de las cajas que están posicionadas absolutamente
    • Evita los saltos dentro bloques que tengan un borde, dentro de las tablas (table) y dentro de los elementos flotados.
  • Tablas e impresión:
    La gestión de las tablas en los medios impresos siempre ha sido fuente de problemas. En el reciente WD del consorcio "CSS Table Module Level 3" abordan la cuestión.
    Especialente en el punto 5: fragmentation dedicado a la eso, la ruptura de las tablas entre páginas y la repetición de encabezados en cada salto.
  • Los elementos con position: fixed; se repetirán en todas y cada una de las páginas impresas.
  • Es conveniente que en la impresión ocultes display: none; todos los elementos superfluos. Cosas como sidebars, banners publicitarios, menús de navegación...
  • Quien tiene la preferencia a la hora de imprimir o no los fondos (ya sean imágenes o colores) es el usuario en la opción que los navegadores tienen para este propósito.
  • El destino de los enlaces quedarán inaccesibles. Si deseas que en la impresión se vean esos destinos puedes utilizar el el pseudoelemeto :after (o :before):

    a:after { content: "(link: " atr(href) ")"; }

  • No utilices medidas en píxeles. Recuerda que es algo propio de pantallas. Los textos en puntos (pt), al menos el valor del elemento raíz o en @page. Después ya podrás utilizar las unidades relativas (em, %, rem). Para los tamaños (anchos/altos) lo suyo es que los definas en cm/mm. Recuerda que estás en un medio físico.
  • Chrome tiene la mala costumbre de mostrar el box-shadow como color sólido. No respeta el canal alfa ni la "difuminación" y lo genera en toda la caja, no a partir del borde. Así que si lo declaras en un elemento sin background obtendrás un bonito bloque del color sólido.

Notas finales

Nota 1↑: En puridad los medios paginados (por ejemplo, papel, transparencias, páginas de álbumes de fotografías, simulaciones de salida impresos) son aquellos en los que se divide el contenido de todo el documento en una o más superficies (por ejemplo hojas de papel) a diferencia de los medios continuos.

Artículo publicado originalmente el 11 de mayo de 2012. Corregido y ampliado sucesivamente desde entonces. Puedes ampliar esta información con los artículos:

Ramajero Argonauta, Enredique Amanuense de CSS.
#impoCSSible inside
Dicen que, en español, EsCss es el mejor blog de CSS. Posíblemente exageren.
@Kseso EsCss Don Kseso Kseso

Comentarios: 20

  1. Genial, gracias por el aporte, solo queria contarte un detalle ortográfico, tu dices "horientación" y es "orientación".

    Saludos,

    ResponderEliminar
  2. Anónimo1/11/12

    Muchísimas gracias por la información.

    Sabes si es posible poner un pié de página mediante algún estilo css? Se que indicas que con position:fixed los elementos se repiten, pero la idea es como indicar al elemento se muestre en el pie de una página definida con tamaño A4.

    Gracias de nuevo.

    ResponderEliminar
  3. La declaración "position: absolute" lo coloca en la posición marcada por las propiedades de ubicación (top-right-bottom-left) sólo en la página impresa en la que aparece el elemento.

    Así que sería cuestión de situar esa caja para que aparezca en el flujo del html en la página deseada. Y con "bottom: 0" posicionarla en la parte inferior.
    Claro que habrá que evitar solapamientos.
    Y si es necesario ocultarla para los demás media.

    Espero que estas indicaciones te sirvan como orientación. Sin los códigos particulares y concretos es demasiado atrevido y arriesgado, además de imposible, elaborar una respuesta ad hoc.

    Un saludo

    ResponderEliminar
    Respuestas
    1. hermanaso como hago para colocar un encabezado que se repita en todas las hojas sin que este se superponga en el resto del contenido... es decir que el encabezado no se monte en el resto del texto.

      Eliminar
    2. Hola Bolivar
      La primera parte de tu consulta (cómo hacer que un elemento se repita en todas y cada una de las páginas impresas) lo tienes respondido en el primer punto del apartado Notas finales del artículo. Declarando position: fixed

      La segunda, cómo evitar los solapamientos con otro contenido, igual que en el media screen: dejando un hueco vacío en todas y cada una de las páginas de igual tamaño que su encabezado.
      Bien con margin o padding superior declarado en la regla @page { }

      Lógicamente deberá hacerlo en su archivo css para el media print.

      Un saludo

      Eliminar
  4. Imprimir una página web siempre fue una tragedia.
    El mejor método al final era llamar a una versión *.pdf o *.rtf (¿todavía existe?) para que la impresora use un documento especialmente hecho para ella.

    Ahora estoy viendo que tenemos muchos más recursos. Algunos muy peligrosos, como el propietario de 'webkit' para pisotear la configuración del usuario imprimiendo los colores de fondo aunque éste no quiera.

    [code]@media print {
    body {-webkit-print-color-adjust: exact;}
    } [/code]

    Igual que no imprime en el 'body', sino en sus hijos. Y bastante mal, porque a ese detalle que mencionaste sobre las sombras opacas, sumemos la mala interpretación de los gradientes (especialmente la dirección). Si hacemos un "dibujo" con fondos que represente un ícono, una viñeta o algo así, cabe la posibilidad de que en el papel aparezca cualquier cosa.

    ResponderEliminar
  5. hola, y si se quiere cambiar el estilo de fuente y color de la misma se puede? por que eh intentado y no logro hacer que la cambie.

    ResponderEliminar
    Respuestas
    1. Hola Max.
      La regla @font-face también aplica en el media='print'. Así que sólo deberías asegurarte que la declaras correctamente tanto en su formulación como regla como que el media en en el que está no excluye a la impresión.

      Respecto al color:
      Igualmente es funcional la propiedad color con la misma advertencia sobre el media en la que se declare.
      Pero además ten presente que la impresión en color o b&n en última instancia es controlada por el usuario a través de sus preferencias de impresión (como los fondos de colores o imágenes).

      Un saludo

      Eliminar
    2. Si la verdad con lo del color es muy raro, por que en las opciones de impresión del navegador, selecciono imprimir a color, pero no me muestra los colores del texto que si tiene color. Otra consulta sabes si se pueden setear por defecto de alguna forma las opciones imprimir a color y gráficos de fondo? para que aparezcan por defecto, ya luego el usuario elegirá si desea quitarlos.

      Eliminar
    3. No. No se puede acceder a ello por una cuestión de seguridad.

      Eliminar
  6. Me gusta el estilo retro de tu masterpage.

    ResponderEliminar
  7. otra duda que tengo con este tema de la impresion, es la de los saltos de paginas, tengo una vista tipo con una tabla con productos, el problema es que cuando hay muchos productos, estos me quedan por debajo del footer (con position: fixed) y no logro hacer que se corte la tabla y que continue en otra hoja.
    te agradecria muchisimo si pudieras ayudarme :)

    ResponderEliminar
    Respuestas
    1. me olvide de aclarar que en mi tabla de productos que es la que quiero que se corte y siga en otra pagina, usea page-break-inside, no se si sea el correcto :P

      Eliminar
    2. Habría que esperar al autor del artículo o alguien con experiencia en impresiones desde páginas web. El propio no es ninguno de los dos casos, pero ya que estoy comento lo que se me iba ocurriendo mientras leía tu consulta.

      No sé a qué llamás "footer". Si es el pie de página de la hoja impresa, es asunto de su impresora, porque allí tendrá configurados el número de folio, la fecha, el nombre del archivo origen,..., en definitiva, lo que el usario quiera ver. Y si queda encimado con algo es su problema de configuración. Si es a tu elemento "footer" en el documento web, pues simplemente le quitás la posición fija, como corresponde, y que aparezca al final de la impresión una vez como ocurre en la pantalla.

      (Si hay alguna identificación o publicidad que ponés en el elemento "footer" para que se vea en cada página, vas a tener que reservar el espacio en el lugar previo a cada salto, que no parece algo incluido en el estándar.)

      Lo de cortar una tabla no está recomendado en ninguna parte, de hecho, el truco usado en HTML para fijar los puntos de salto era justamente meter los bloques del documento en tablas, porque no se cortan. Si el tamaño es mayor al de la hoja, el soft de impresión se encarga de achicarla o de cortarla por las suyas. No veo que exista un equivalente al elemento "wbr" en saltos de línea para los saltos de página, y si lo hubiera debe tener la misma recomendación de evitar el uso en las filas de tablas, que sería el lugar natural para ponerlo (o a su equivalente CSS).

      Como sugerencia, si tenés un imprimible tan complicado no lo hagás en HTML. El lenguaje es para páginas web, no para ver estático en una hoja de papel. Si lo quieren ver impreso, que se bajen la versión en *.pdf o *.docx que sí son documentos imprimibles. Claro que si tus tablas son dinámicas y cambian valores y tamaños constantemente, vas a necesitar algo de trabajo en servidor para crear estas versiones.

      Eliminar
    3. Hola Max. Veo que sigue tu pelea con las tablas y su impresión.

      Poco tengo que añadir a la respuesta de Furoya.
      En este tema no ha habido avances significativos (que yo conozca) en css y html y en el manejo de ellas por los navegadores al ser enviadas a un medio paginado como es la impresión.
      Hace poco tiempo estuve leyendo el nuevo documento "CSS Table Module Level 3" del del CSS Working Group.
      En especial el punto 5, "Fragmentation", hace referencia al tema. Pero es algo que tardará.

      Me comentaba Furoya que estuvo haciendo pruebas creando la tabla con div´s y otros elementos html y las propiedades display: table y asociadas.
      Pero tuvo los mismos problemas con el page-break-inside.
      Yo había pensado en el camino inverso: cambiar el display de la tabla y sus hijos a blocks e inline-blocks en el media print.
      Tengo mis dudas que sea una opción viable. Pero hasta no hacer las pruebas oportunas...

      Espero que al final encuentres cómo hacerlo y que nos compartas tu solución. Aunque repito mi creencia de que hoy por hoy ha de ser con otros recursos que CSS.

      Un saludo y mis disculpas por el retraso en contestarte.

      Eliminar
    4. No quiero ser pesado, pero tenía un minuto y lo aproveché para hacer algunas pruebas más. Ya que tenemos publicada la consulta, vamos a ampliar aunque sea un mínimo el tema.

      Dije que antiguamente las tablas no se cortaban, a menos que no entraran en la hoja, y entonces la impresora las dividía como a cualquier imagen. Ya no ocurre eso, ahora las corta siempre, así que tu problema está resuelto, Max Saavedra. Salvo por el detalle de la altura de filas, porque no las respeta como bloque y si el contenido de una no cabe en la hoja, lo empieza en la primera y lo termina en la segunda. Y eso sí se tiene que correjir poniendo 'page-break-inside:avoid' en las 'tr'. Lástima que sólo funciona en Mozilla's.

      La opción de un link alternativo para impresión como
      '<link rel=alternate media=print href="tabla.pdf">'
      resulta que tampoco anda en ninguno. Aunque siempre se puede poner un enlace que diga "Versión imprimible" y que lo piquen.

      Eliminar
    5. Muchas gracias por sus respuestas, sigo paliando con este tema la verdad, con respecto a lo de mozilla, si que es mala suerte por que la app que estamos desarrollando es para chrome ya obviamente al ser de google es el que de momento soporta muy bien material design, así que de momento estamos "descartando" mozilla. Si logro algún avance lo estaré compartiendo con ustedes. Un saludo

      Eliminar
    6. Otra duda en caso de querer directamente generar el PDF desde el BackEnd, saben como levantar ese pdf en la vista de impresión, como lo hace google docs o microsoft con office online?
      Vi ejemplos con el tag object de html, pero no me quedaron muy claros...

      Eliminar
    7. Buenas, les cuento que ya logre solucionarlo con un PDF desde el BackEnd y lo levanto en el navegador como si se tratara de una pag a imprimir desde el FrontEnd. Si les interesa voy a preparar un plunker con un ejemplo, y se los comparto... Un saludo

      Eliminar

EsCss RSS del Blog RSSS Comentarios Humans.txt ᛯ Diseno por Kseso SiteMap