Wextensible

Imprimir páginas web

Usando CSS para configurar impresión de la página

Imprimir web

En este sitio aún no había configurado nada a la hora de imprimir. Realmente no es muy necesario pues ya casi nadie imprime una web. De todas formas en estos días he actualizado el contenedor de código resaltado incorporando una barra de botones con varias funciones. Una de ellas es la de imprimir ese trozo de página. En base a esto he realizado algunos cambios para poder imprimir una página o bien un trozo de ella.

En el tema CSS 2.1 Medios paginados se expone algunas cosas que podemos hacer con CSS para configurar las páginas a la hora de imprimir. Usando la regla @media print podemos declarar estilos sólo para la salida impresa. Recordemos que cuando no se declara ningún medio se entiende que el estilo se aplica por defecto al medio screen, es decir, al medio visual.

El estilo de este sitio lo tengo estructurado en tres archivos CSS con el objeto de definir el estilo de cada zona de la página. Esto es práctico a la hora del mantenimiento. Un archivo es cabeza-pie.css con el estilo para la cabecera, botonera de vínculos, "migas" y pie de página. Últimamente también he incluido los Sprites CSS en este archivo. En definitiva, todo el estilo de la estructura común de cabeceras y pies de página del sitio. Otro archivo es interior.css con el estilo para la estructura interna de la página, es decir, todo lo que hay entre cabecera y pie de página. Se declara el número y anchos de los laterales y del contenido que hay entre ellos. También hay otros estilos también que se incluyen en el contenido como una barra navegadora de temas o los submenús con bordes redondeados que hay en la página de inicio. Y por último tenemos formatos.css con estilos diversos para tipos de letras, colores, formatos de tabla, etc. Esta hoja puede ser usada independientemente de las otras dos.

Ahora he modificado el archivo cabeza-pie.css para que también contemple la salida impresa. Realmente lo único que he hecho es agregar este código en el inicio del archivo:

@media print {
#botonera, #migas, #marcas-sociales, #pie, .navega-temas, .lateral {
    display: none;
    }
.lateral {
    width: 0;
    }
#contenido {
    margin-left: 0;
    margin-right: 0;
    }
}

Se trata de eliminar aquellos aspectos de la página que no resultan interesantes a la hora de imprimir, quedando sólo el verdadero contenido. En todas las páginas quitamos la botonera de vínculos de la cabecera, las migas, la barra de marcas sociales (botones "me gusta") y el pie de página. En otras páginas se incluye un barra navegadora de temas (navega-temas) al finalizar el contenido que tampoco tiene utilidad a la hora de imprimir. También se quitan los laterales, por ejemplo los que aparecen en la página de inicio, pues son al final una colección de vínculos y otras cosas sin interés para imprimir. A estos laterales se les anula el ancho y al mismo tiempo al contenido que está entre ellos se les quita los márgenes derecho e izquierdo para que se expanda hacia ambos lados.

La regla @page y otras propiedades de estilo relacionadas con medios paginados permiten hacer otras cosas. Aunque todos los navegadores no se comportan igual en este aspecto por lo que no haré nada más por ahora.

Imprimir una parte de una página web

En estos días he actualizado el contenedor de código resaltado, acompañando una barra de botones para imprimir y numerar líneas. En este apartado explicaré como imprimir un trozo de una página web, mejor dicho, el contenido de algún elemento de la página. Veámos primero un ejemplo en funcionamiento:

Ejemplo:

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc eu lectus nulla, a volutpat sem. Pellentesque ut lectus non sem hendrerit pellentesque vestibulum nec turpis. Donec sem sapien, aliquam vitae laoreet a, ultrices eget ante. Nam condimentum enim eget sapien semper egestas. Nulla bibendum turpis sapien, vel vehicula felis. Cras auctor, odio a ultricies vulputate, mauris tellus hendrerit urna, vel consectetur tellus nisl eu nisi. In erat ligula, rhoncus sit amet laoreet eget, volutpat non metus. Integer in eros massa. Mauris iaculis vestibulum tincidunt. Suspendisse ornare ante quam. Aliquam erat volutpat. Cras at diam lacus, et sagittis erat. Nullam sed quam augue, quis consectetur lectus. Morbi tristique dictum lobortis.

Este ejemplo tiene el siguiente código en el HTML para imprimir el contenedor con el texto Lorem ipsum... identificado con id="prueba-imprimir":

<script>var linkFormato = '<link rel="stylesheet" href="/res/sty/formatos.css" />';</script>
<input type="button" value="Imprimir esto"
onclick="imprimirTrozo(document.getElementById('prueba-imprimir'),linkFormato,true)" />
<div id="prueba-imprimir">
    Lorem ipsum...
</div>

Con JavaScript declaramos una variable linkFormato con un literal HTML de un elemento del <head> del documento que vamos a generar. Luego llamamos a la función imprimirTrozo(elemento, inHead, vistaPrevia) que aplicamos para imprimir el contendor de prueba. El argumento inHead sirve para pasar a la función cualquier cadena literal HTML que podamos meter en el <head> del documento. En el ejemplo uso el estilo del archivo formatos.css que es el que da el color verde al borde y texto del recuadro. El tercer argumento es obvio, un booleano para una vista previa del trozo o imprimirlo directamente. La función imprimirTrozo() está ubicada en el módulo general.js para tenerla disponible en cualquier página del sitio. Tiene este código:

function imprimirTrozo(elemento, inHead, vistaPrevia) {
    if (elemento) {
        //Construimos un documento HTML mínimo
        var cadhtml = '<!DOCTYPE html>' +
        '<html lang="es"><head>' +
            '<meta http-equiv="content-type" content="text/html; charset=UTF-8" />' +
            '<title>Imprimir</title>' +
            '<link rel="stylesheet" href="/res/sty/cabeza-pie.css" />' +
            '<style>' +
            '@media print {' +
                'div[data-sprite-src] {' +
                    'display: none;' +
                    '}' +
                '.contenedor-imprimir {' +
                    'border: 0;' +
                    '}' +
                '.contenedor-imprimir > * {' +
                    'height: 100% !important;' +
                    '}' +
            '}' +
            '@media screen {' +
                '.contenedor-imprimir {' +
                    'border: gray solid 1px;' +
                    '}' +
                '.contenedor-imprimir > * {' +
                    'height: 100% !important;' +
                    '}' +
            '}' +
            'body {' +
                'background-color: gray;' +
                '}' +
            '.contenedor-imprimir {' +
                'width: 100%;' +
                'background-color: white;' +
                'word-wrap: break-word;' +
                '}' +
            'div[data-sprite-src] {' +
                'width: auto;' +
                'color: orange;' +
                'font: 30px Georgia;' +
                'font-style: italic;' +
                'padding-left: 35px;' +
                'margin-bottom: 5px;' +
                '}' +
            'div[data-sprite-src] > * {' +
                'vertical-align: middle;' +
                '}' +
            '</style>' +  inHead +
        '</head><body>' +
            '<div data-sprite-src="/res/img/logo.gif">wextensible.com ' +
            '<input type="button" value="Imprimir" onclick="window.print()" /></div>' +
            '<div class="contenedor-imprimir">' + elemento.outerHTML + '</div>' +
        '</body></html>';
        //Lanzamos una ventana con este contenido
        var ventana = window.open("", "Imprimir");
        //Abrimos un nuevo documento en esa ventana
        ventana.document.open("text/html");
        //Opera necesita que esté la ventana cargada para imprimir. Esto
        //no le importa a Firefox, Chrome o Safari, pero así también funciona.
        //Hemos de declarar el load después de hacer el open()
        if (!esNavegador("msie") && !vistaPrevia) {
            //IE8 no responde con esto, lo haremos luego
            ventana.window.onload = function(){
                ventana.print();
                ventana.close();
            };
        }
        ventana.document.write(cadhtml);
        ventana.document.close();
        //Esto es para IE8
        if (esNavegador("msie") && !vistaPrevia){
            ventana.print();
            ventana.close();
        }
    }
}

Se trata de montar un documento completo y volcarlo en una nueva ventana usando el método de JavaScript document.write(). En primer lugar se construye un literal HTML con lo imprescindible. Agregamos estilo necesario para configurar tanto la página de vista previa a mostrar en pantalla con la regla @media screen así como para la versión de imprimir con @media print. He decidido poner este estilo dentro del documento pues no se va a utilizar en ningún otro sitio. Con el argumento inHead incorporamos los elementos que necesitemos como <link>, <style> o <script>. En el ejemplo anterior incorporamos el estilo del archivo formatos.css que nos pintará el texto en color verde. En el <body> personalizamos el contenido con el nombre del sitio o cualquier cosa que queramos poner. El literal HTML del elemento lo extraemos con outerHTML.

Tras construir la cadena literal HTML del documento el proceso es el siguiente para cuando estamos solicitando la vista previa:

  1. var ventana = window.open("", "Imprimir"): Creamos una nueva ventana en el navegador con el título "Imprimir".
  2. ventana.document.open("text/html"): En esa ventana abrimos un nuevo documento con mime type text/html.
  3. ventana.document.write(cadhtml): Escribimos el literal HTML en el documento.
  4. ventana.document.close(): Cerramos el documento. Esto le dice al navegador que ya no se va escribir más nada en ese documento.

Si estamos imprimiendo directamente (argumento vistaPrevia es false) entonces antes de escribir el documento declaramos un evento window.onload para enviar a imprimir con ventanta.print() y luego cerrarla con ventana.close(). Esto para todos los navegadores consultados a excepción de Internet Explorer, pues sólo funcionará si lo hacemos después de cerrar el documento (document.close()).