La regla @page y estilos para impresión en CSS

Si bien es cierto que cada día es menos habitual imprimir cosas desde la web muchas veces puede interesarnos tener un formato específico para la impresora que nos permita ocultar menús. A la hora de meter un formato sólo para la impresora procederemos como con cualquier CSS normal, pero añadiendo en la etiqueta media=»print», como en el ejempo:

<!-- Cargando un CSS externo -->
<link href="paraimprimir.css" type="text/css" media="print" />
<!-- Insertando CSS en la cabecera -->
<style type="text/css" media="print">
/*aquí lo que corresponda*/
</style>
<!--También puede usarse esta sintaxis-->
<style type="text/css"> 
  @media print { 
      /* reglas css */ 
  } 
<style>

Con estos estilos, por ejemplo, podemos hacer que un elemento aparezca en todas las páginas definiéndolo como fixed u ocultar lo que no tenga sentido mostrar en la impresión con display:none.

El uso de media print genera una caja CSS distinta a la de pantalla (media screen) para alojar los contenidos, a pesar de que su boxmodel será el mismo. Esta caja se conoce como page y podremos acceder a ella para modificar sus características mediante el selector @page.

Dicho selector nos permite, por ejemplo, definir la orientación de la página entre normal y apaisada:

/*Orientación vertical*/
@page {size: portrait;}
/*Orientación apaisada*/
@page {size: landscape;}

También podemos utilizar clases ligadas a la regla page, por ejemplo imaginemos que queremos imprimir un informe con todas las páginas en vertical pero con las tablas y las gráficas apaisadas en una hoja aparte:

@page apaisada {size: landscape;}
table {page: apaisada; page-break-before: right;}
/*las gráficas las diferenciaremos con una clase CSS*/
.poll {page: apaisada; page-break-before: right;}

A la hora de definir el tamaño de la página debemos tener en cuenta que su total será la suma del contenido más los bordes (margin y padding), y podemos definirlo con el atributo size. Podemos utilizar valores numéricos (porcentajes, puntos, centímetros, milímetros), excepto píxeles porque pertencen al ámbito de la pantalla, o utilizar los diversos valores que definen tamaños standares de papel (A4, A3, letter). En caso de no especificar nada el tamaño será auto, que es el valor por defecto. Lo suyo es utilizar las medidas de los textos en pt y el alto y ancho de página en cm, mm o in (pulgadas), piensa que trabajamos sobre un medio físico y no sobre una pantalla que puede tener diversos tamaños y resoluciones.

@page {
  size: 8.5in 11in;  /* ancho y alto en pulgadas */  
}
@page {
  size: 21cm 190mm; /*medidas en tamaño*/
}
@page {
  size: A4; /*standar A4*/
}

Disponemos además de las pseudoclases :first, :left y :right que nos permitirán perfeccionar nuestra maquetación para la impresión a dos caras y pudiendo usar unas reglas específicas para la primera página.

/*Para la primera página usaremos un margen superior e izquierdo muy grande*/
@page :first {
  margin-top: 6cm;
  margin-left: 7cm;
}

/*definimos los márgenes de la página izquierda*/
@page :left {
  margin-right: 4cm;
  margin-left: 3cm;
}

/*y para la derecha invertimos los valores
para que la impresión a doble página
quede bien*/
@page :right {
  margin-right: 3cm;
  margin-left: 4cm;
}

Y también podemos definir cuántas líneas de un párrafo queremos dejar al final de una página como mínimo o al principio, con la intención de no dejar líneas huérfanas o viudas. Para ello disponemos de las propiedades orphans y widows (que significan huérfanas y viudas en inglés).

@page{
  orphans:5;
  widows:4;
}

¿Cómo funcionaría el ejemplo de arriba? Imaginemos que al final de una página caben 15 líneas. Si tenemos justo 15 o menos entrarán en esa página. Si tenemos 17 entonces, para no violar la regla, se repartirían 13 en la página 1 y 4 en página 2 (para cumplir el mínimo), y su tuviéramos 19 o más no habría problema: 15 en la primera y el resto en la siguiente.

Finalmente hablaremos de los saltos de página, que ya vimos en uno de los ejemplos de arriba. Y es que los elementos de bloque pueden llevar asociado un salto de página, que puede ir antes, después o dentro del elemento. Para ponerlo antes usaremos page-break-before y para hacerlo después iría page-break-after. Para hacerlo dentro usaremos page-break-inside, que tiene la particularidad de que se puede heredar del elemento contenedor mientras que los otros dos no. Para page-break-after y page-break-before puede haber cuatro valores:

  • always: fuerza siempre un salto de página antes o después del elemento, según corresponda
  • avoid: evita siempre un salto de página antes o después del elemento, según corresponda
  • left: fuerza los saltos de página que sean necesarios para que la siguiente página sea compuesta como una página izquierda
  • right: fuerza los saltos de página que sean necesarios para que la siguiente página sea compuesta como una página derecha

Y creo que con esto hemos recorrido los puntos principales el tema de los estilos CSS para impresión.

Instalando Google Web Designer en Linux

Hará cosa de un año Google nos sorprendió con una herramienta de diseño web en fase beta: Google Web Designer. Un editor WYSIWYG muy potente, gratuito (al menos de momento), orientado hacia diseñadores, pensado para sacar todo el jugo de HTML5 y CSS3 (diseño responsivo, animaciones, aceleración 3D) y a su vez ser sencillo. Y, al igual que hicieron con Google Drive, se olvidaron de los usuarios de Linux.

Google-Web-Designer

Lo curioso es que se preguntó al director de proyecto alguna vez que qué pasaba con los Linuxeros y la respuesta fue más sorprendente: sí existía una versión para linux que además se usaba internamente en la empresa, pero tenía diferencias respecto a la que salió para Mac y Windows, por lo que no la sacaban. Al final, tras mucha presión por la comunidad, anunciaron que sí sacarían la versión para Linux.

Y ya la tenemos.

¿Cómo la instalamos? Sencillo: Vamos a la web del proyecto y desde allí descargamos el archivo .deb que mejor vaya con la distribución de Linux con la que trabajemos, lo ejecutamos con nuestro instalador de paquetes y… listo. Ya está, todo muy fácil… ¿o no?

Pues voy a ser jodón, pero no. Si fuera tan fácil no haría una entrada en el blog. Resulta que de momento hay un bug con la carga del idioma, si vuestro sistema no está en inglés Google Web Designer sólo muestra una ventana negra y no carga, no funciona. Por suerte por los foros oficiales ya existe una solución, que os obligará a tirar de consola (hasta que no salga una actualización/parche al menos)

#Lo primero es cargarnos la configuración por defecto tecleando:
sudo rm -r .local/share/google-web-designer

#y ya podemos lanzar web designer desde la consola, forzando que lo haga en inglés, con el siguiente comando
LANGUAGE=en_US google-webdesigner

Ahora sí, con esto ya tenéis funcionando Google Web Designer en vuestro equipo con Linux. Esperemos que dentro de poco la gente de Mountain View se apure a sacar o traducciones o al menos un parche que evite este molesto bug.

Etiquetas para convertir webs en web-apps Android

No hace mucho os hablaba aquí de una serie de etiquetas creadas por Apple que permitían hacer que una web luciera como una aplicación nativa de iOS, y comentaba que era una pena que no hubiera algo así para Android… pero lo cierto es que lo hay. A partir de la salida de Chrome 31 para Android el sistema operativo de Google también da opción a hacer esto mismo, aunque he de admitir que no dan tanto juego como las de Apple, y como estos se han dedicado (como es su filosofía de empresa hermética/cabrona/malvada) a no documentar ni compartir una mierda hay que andar buscándose la vida. Por cierto que Mozilla también nos permite crear web-apps facilitas tanto para su sistema operativo FirefoxOS como para Amazon Kindle Fire y Android si usas Firefox.

De primeras no hay una etiqueta especial para el título del app, deberéis utilizar la meta etiqueta title normal. Tampoco existe un equivalente de la propiedad navigator.standalone de iOS, que nos devuelve un boolean si estamos ejecutando el app a pantalla completa. En todo caso, con este truquito podemos lograr lo mismo:

navigator.standalone = navigator.standalone || (screen.height-document.documentElement.clientHeight<40)

El Javascript ejecutadlo siempre después de que la página esté totalmente cargada (tras el evento onload()), por si los scrolls.

Vamos ahora con los puntos fundamentales. El primero: forzar el modo web-app, que se consigue con la siguiente etiqueta:

<meta name="mobile-web-app-capable" content="yes">

Vamos, lo mismo que la de iOS quitándole el prefijo «apple». El segundo punto clave ¿cómo añadir al escritorio el app? Bueno, la primera vez que llegáis a la página, en el menú del navegador os encontráis una opción que será “Add to homescreen” (lo he probado en emulador y tengo Chrome en inglés, no estoy seguro de cómo se llama la opción en castellano). En cuanto al icono, si habéis puesto el de Apple Touch lo cogerá por defecto, si bien la especificación de google recomienda incluir uno cuadrado de 196*196, tal que aśi:

<link rel="shortcut icon" sizes="196x196" href="vuestroIcono.png">

Un último punto, los enlaces se abrirán por defecto en el contexto de la aplicación, si queréis abrir un enlace concreto en una ventana de Chrome (por ejemplo una referencia a una web externa) insertad el atributo target=»_blank» en el link.Otro punto, no tenéis el botón de recargar del navegador (al estar en ese contexto sin marco), así que si queréis tener una opción de «refresh» tendréis que implementar una solución en javascript.

En fin, queda mucho por andar en este terreno, pero parece que Google se pone al fin las pilas, y Mozilla ya lleva mucho currando (y al contrario que Apple ellos sí hacen las cosas de forma abierta).

Crear un hexágono o un octógono con CSS

Se está poniendo de moda el usar formas geométricas en las maquetaciones así que ¿cómo podemos crear un hexágono para nuestra web? ¿o un octógono? En el último año de hecho los hexágonos han estado bastante de moda (parece un chiste, pero no, pensad en múltiples diseños que habéis visto)

Entonces ¿cómo creo un hexágono con CSS? Pues aquí va un ejemplo de código, basándose en un la idea de que, a fin de cuentas, un hexágono se hace con un cuadrado con un triángulo encima y otro debajo:

#hexagono { 
  width: 150px; 
  height: 90px; 
  background: #666; 
  position: relative; 
}

#hexagono:before { 
  content: ""; 
  position: absolute; 
  top: -50px; 
  left: 0; 
  width: 0; 
  height: 0; 
  border-left: 75px solid transparent; 
  border-right: 75px solid transparent; 
  border-bottom: 50px solid #666; 
} 
#hexagono:after { 
  content: ""; 
  position: absolute; 
  bottom: -50px; 
  left: 0; 
  width: 0; 
  height: 0; 
  border-left: 75px solid transparent; 
  border-right: 75px solid transparent; 
  border-top: 50px solid #666;  
}

Ya véis la idea: usando :after y :before metemos dos triángulitos sobre un cuadrado y ya tenemos hexágono.

El octógono ya es más jodón, que tiene más lados, pero tampoco entraña mucha más complejidad. Eso sí, vas a necesitar jugar con más colores, ya que las formas se hacen a base de bordes, como en el ejemplo anterior:

#octogono { 
  width: 150px; 
  height: 150px; 
  background: #999; 
  position: relative; 
} 
#octogono:before { 
  content: ""; 
  position: absolute; 
  top: 0; 
  left: 0; 
  border-bottom: 44px solid #999; 
  border-left: 44px solid #fff;/*Para el ejemplo he elegido blanco, poned vosotros el color de fondo de vuestra web. No uséis transparent porque entonces se verá el color de fondo del cuadrado*/ 
  border-right: 44px solid #fff; 
  width: 63px; height: 0; 
} 

#octogono:after { 
  content: ""; 
  position: absolute; 
  bottom: 0; 
  left: 0; 
  border-top: 44px solid #999; 
  border-left: 44px solid #fff; 
  border-right: 44px solid #fff; 
  width: 63px; 
  height: 0; }

Acceder a los elementos de un Iframe con Javascript

Un tip rápido de Javascript: Tienes un iframe en tu página y quieres acceder a los elementos que hay dentro. ¿Es posible hacerlo? Sí pero no. Me explico:

Si el iframe está en el mismo dominio que la página padre sí, si no, por motivos de seguridad, el navegador no te lo permitirá.

En caso de que la respuesta a si está en el mismo dominio sea afirmativa puedes acceder al iframe por su id, ya que habrá un objeto donde estarán guardados todos, y una vez accedido a él puedes llegar a sus elementos a través de su id. Un ejemplo simple:

// cambia miFrame por el id de tu iframe,
// cambia idDelElemento por el id que corresponda,
// puedes trabajar con los elementos del iframe como si fueran parte de la página padre.
window.frames['miFrame'].document.getElementById('idDelElemento')

Añadiendo elementos al DOM con Javascript: appendChild e insertBefore

Una de las funcionalidades potentes de Javascript es poder generar nuevo código dinámicamente y añadirlo a nuestra web, cosa que podemos hacer con las funciones appendChild e insertBefore.

El método appendChild nos permite insertar un elemento dentro de otro, al final del mismo. Imagina que quieres agregar un elemento a una lista que sea «nuevo elemento«, pues javascript permite crear este nuevo elemento, meterle un nodo de texto y agregarlo a la lista. Veamos como:

elemento1 = document.createElement('li');
elemento1.appendChild(document.createTextNode('nuevo elemento'));
elemento2 = document.getElementById('laListaQueYaExiste');
elemento2.appendChild(elemento1);

¿Y si quieres insertar al principio en lugar de al final de la lista? Pues tan simple como usar insertBefore:

elemento1 = document.createElement('li');
elemento1.appendChild(document.createTextNode('nuevo elemento'));
elementoLista = document.getElementById('laListaQueYaExiste');
//hasta aquí todo igual
elemento2 = elementoLista.firstChild();
//en la línea de arriba creamos un elemento nuevo que es el primer elemento de la lista.
elemento3.parentNode.insertBefore(elemento1,elemento3);
//también podríamos haberlo hecho así:
elementoLista.insertBefore(elemento1,elemento3);

Detectar si un usuario usa Adblock Plus

El tema de la publicidad en internet está candente últimamente. Por un lado algunas páginas se pasan de publicidad intrusiva (y no hablo sólo de sitios donde ver retransmisiones deportivas on-line, basta con entrar en la web de cualquier periódico español «grande» para ver anuncios que a veces hasta dificultan la lectura), pero por otra parte también están muchas webs gratuitas cuya única fuente de ingresos es la publicidad, y al bloquearla les dejamos sin un dinero necesario para pagar los gastos ocasionados. Algunas web optan por bloquear a los usuarios que llegan con el adblock puesto, yo no comparto estas medidas draconianas ya que soy el primero que ve eso y lo siguiente que hace es salir de la página y buscar otra que me ofrezca lo mismo sin esta publicidad. Creo que la mejor solución sería el «buenrollismo«, vamos, que si se detecta en AdBlock se le saca al usuario un aviso tipo «tío, que alojamiento y dominio son 50 pavos anuales, que no es mucho pero me los sacaba con estos anuncillos de google, no me jodas y saca el bloqueador, man». La mayoría no te harán ni caso, pero bloqueándoles no te creas que lograrías mejores resultados, al menos así puede que lo compartan en redes sociales y logres ingresos de otros usuarios que lo miren.

Vamos pues con la chicha ¿cómo se detecta AdBlock? Bueno, yo lo he hecho mediante el método del señuelo, que de momento va furrulando. La cuestión es que AdBlock tiene una lista negra de palabras y bloquea según qué javascript si detecta alguna de ellas. El truco es meter un javascript con un nombre que haga saltar Adblock, comprobar que dicho javascript no está furrulando y, en ese caso, lanzar un aviso al usuario.

Empezamos creando un archivo de javascript con el título advertisement.js, un nombre que hará saltar a Adblock para evitar su carga, con un contenido más o menos como el siguiente:

document.write('<div id="le_truquito">Publicidad malvada y terrible!!</div>');

La idea es hacer el document.write de un div con un id concreto, lo del texto ya es chorrada mía. Por si entra un usuario sin Adblock lo mejor es que ocultemos ese div que se creará con CSS, para que no le aparezca por medio.

#le_truquito{
    display:none;
}

Ok, lista la trampa lo siguiente es añadir otro código de javascript que comprobará si se ha bloqueado el primero (cerciorándose de si existe el div que debería crear) y, en caso de que no lo haya hecho sacará un mensaje en pantalla.

<script type="text/javascript">
if (document.getElementById("le_truquito") == undefined)
{
    window.alert("tío, que alojamiento y dominio son 50 pavos anuales, que no es mucho pero me los sacaba con estos anuncillos de google, no me jodas y saca el bloqueador, man");
}
</script>

En el ejemplo puse un window.alert, pero también podéis crear un div con un texto en la página… en fin, lo que veáis más práctico.

De momento el sistema funciona, y tiene pinta de que al menos durante una temporada lo hará. En todo caso podéis buscar el nombre de un archivo de javascript de publicidad de Google, o de otra compañía, que sepáis positivamente que se está bloqueando por AdBlock y llamarle así en lugar de advertisement.js (aunque de momento con ese nombre furrula).

Meta etiquetas de Apple para hacer que una web parezca un app para iPhone o iPad

Aunque ya sabéis que le tengo alergia a los iCacharros, y sobre todo a sus fanáticos seguidores, hay que reconocer que Apple de vez en cuando saca cosillas interesantes. Una de ellas es la meta etiqueta viewport de la que ya hablamos en el pasado, pero no es la única meta equita que se sacó de la manga Apple para el diseño web móvil. Y es que dando uso a sus etiquetas podemos hacer que una web aparezca en pantalla como si fuera un app nativa, que se le pueda hacer un acceso directo desde el menú de aplicacione con un icono… todo esto mediante una serie de etiquetas.

Para conseguir que al abrir la web esta se vea sin ningún marco del navegador en pantalla hay que usar la siguiente etiqueta en la cabecera de la web, gracias a la cual lograremos ese aspecto app-like:

<meta name="apple-mobile-web-app-capable" content="yes" />

Sigamos ¿cómo escogemos un icono? Bueno, realmente necesitamos dos iconos, uno para la versión normal y otro para la versión con pantalla de alta densidad (o como reza su nombre comercial «retina display«). El primero ha de ser de 57*57px y la siguiente de 114*114px, la propiedad href apuntará a donde tengáis guardada la imagen:

<link rel="apple-touch-icon" href="img/icons/icono5757.png">
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="img/icons/icono114114.png">

Es posible que al abrir la web/app os salga durante unos segundos una imagen en blanco mientras esta carga (muy posible), algo que queda «feo» pero que tiene también solución: podéis definir una imagen que se muestre durante esta carga, una startup-image:

<link rel="apple-touch-startup-image" href="img/loading.png">

Y finalmente, existe una posibilidad de modificar mínimamente la barra de estado de Apple en la parte superior. No es que tengáis mucho con lo que jugar, no es que haya mucha opción, pero algo se puede ir apañando, pudiendo elegir entre el color por defecto, el negro o un efecto traslúcido.

<!--Por defecto-->
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<!--negro-->
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<!--traslúcido-->
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">

Y con estas opciones podréis hacer que vuestra web parezca un app para dispositivos Apple. La he probado en el curro (web PHP+Javascript) en un proyecto y el resultado fue satisfactorio. La pena es que no haya algo así para Windows Phone y Android.

Uso de los pseudoelementos :before y :after de CSS3

¿Cuántas veces has tenido que poner una coletilla al lado de varios elementos en una web? Por ejemplo, poner la palabra «Error» antes de un mensaje de error. ¿No te encantaría que eso pudiera automatizarse?.

Pues con CSS3 puedes hacerlo. Con los pseudoelementos :before y :after. Estos te permiten añadir un contenido html antes (:before) o después (:after) de un elemento desde vuestra hoja de estilos. Para ello utilizaremos la propiedad «content». Vamos con un ejemplo, en el que añadiremos la palabra «Error» antes de un mensaje de error (vamos primero con lo más simple)

.error:before{
  content:"Error: ";
}

Furrula hasta en IE8 (7 no, no pidáis milagros), así que podéis ir trasteando con esto. Hay más posibilidades, claro, porque si sólo pudiéramos meter un textillo la cosa quedaría sosa. Lo primero, podemos dar estilos al contenido generado por estos elementos, como con cualquier otro elemento textual de la web:

.error:before{
  content:"Error: ";
  color:#FF0000;
  font-weight: bold;
}

O podemos incluir una imagen en lugar de un texto:

.error:before{
  content:url("carpetaimagen/imagenejemplo.png");
}

O crear un contenedor:

.error:before{
  content:"";
  display:block;
  background-color:#666;
  width:32px;
  height:32px;
  border:2px solid #ff0000;
}

Eso sí, hay una cosa que debemos tener en cuenta: a la hora de accesibilidad y del uso de lectores de pantalla, por ejemplo, estos textos/imágenes están generados por CSS, no son parte del DOM, no forman parte del contenido en si de la web, por lo que no serán interpretados por estos. Es decir, mejor no crear contenido relevante con esto, tanto por la accesibilidad como por el hecho de que los buscadores no lo indizarán.

Pie de página siempre al final de la web

Seguro que alguna vez os ha pasado que os trabajáis una maquetación que se ve de puta madre en vuestra pantalla de 15 pulgadas, pero al verla en una 22… ale, el pie al medio de la página. No hay contenido suficiente para llenar toda esa pantalla. Una opción es usar un posicionamiento absoluto, pero claro, si es una web con varias páginas igual en otra sí tienes suficiente contenido y entonces te queda un pie fijo en la parte de abajo del monitor aunque tengas que scrollear para ver toda la info.

Pero hay una solución, básicametne consiste en envolver todo el contenido superior al footer en un div contenedor, darle un alto mínimo del 100% de la pantalla, meterle debajo un margen negativo y allí insertar el pie. Ok, dicho así suena muy árido. Vamos con un ejemplo progresivo. Imaginemos que el que sigue es nuestro código:

<div id="header">Aquí la cabecera</div>
    <div id="nav">
       <ul>
          <li><a href="#">Inicio</a></li>
          <li><a href="#">Primera</a></li>
          <li><a href="#">Segunda</a></li>
       </ul>
     </div>
<div id="content">Contenido interesante y original que te hará ganar posicionamiento en google.</div>

<div id="footer">Y aquí ese pie que no se nos queda abajo.</div>

Bueno, pues lo primero es el marcado (luego ya nos ponemos con el CSS). La idea es, como he dicho, encerrar todo el contenido en un div que será un contenedor general, y por si acaso al final de este metemos un div vacío con la misión de evitar problemas si hay elementos flotados encima.

<div id="container"> <!--El container-->
  <div id="header">Aquí la cabecera</div>
    <div id="nav">
       <ul>
          <li><a href="#">Inicio</a></li>
          <li><a href="#">Primera</a></li>
          <li><a href="#">Segunda</a></li>
       </ul>
     </div>
  <div id="content">Contenido interesante y original que te hará ganar posicionamiento en google.</div>
  <div class="clear"></div><!--El citado div para evitar problemas con "flotaciones"-->
</div><!--cerramos el container-->
<div id="footer">Y aquí ese pie que no se nos queda abajo.</div>

Bueno, eso está listo. Ahora toca ceeseesear (CSS) todo. Como ya he dicho, la idea es dar a todo el contenedor un tamaño mínimo del 100% de la altura, meterle un margen negativo por abajo y allí insertar el pie. Vamos a meter un pie de 50px de alto en el ejemplo.

/*Lo primero, todo el cuerpo que ocupe el 100%*/
html, body {    
   height: 100%; 
}

/*Lo segundo, el container, con algura mínima del 100% y un margen inferior negativo igual al alto que queramos darle al pie*/
#container {
   min-height: 100%;
   margin-bottom: -50px;
   position: relative;
}

/*Lo tercero, el pie con la altura deseada (igual al margen negativo de antes)*/
#footer {
   height: 50px;
   position: relative;
}

/*Y terminamos con el clear, que ha de ser tan alto como el pie y "limpiar" todos los floats*/
.clear{
   height: 50px;
   clear: both;
}

Y con esto ya está, en todos los navegadores superiores a IE6 (y como IE6 está descontinuado por Microsoft ni me voy a molestar en buscar solución, aunque creo que basta con cambiar el min-height del container por height).

Artículo dedicado con cariño a Gaius Baltar, que se lo había prometido en el feisbuck… jojojo