martes, 30 de septiembre de 2014

Patrón fachada en JavaScript (Facade)

Es uno de los patrones más comunes en todo tipo de sistemas. Se utiliza para simplificar una interfaz compleja y reducirla a las funciones necesarias en nuestro sistema o a funciones mejor diseñadas y más simples que las originales. También puede utilizarse para desacoplar un sistema de un subsistema/componente concreto.

La librería jQuery proporciona ejemplos muy bien diseñados de este patrón. El más conocido y más utilizado es el selector de elementos del DOM: $("selector").

Hasta que el W3C definió el Selectors API Level 1, encontrar elementos concretos en el DOM era bastante engorroso si no tenian una id asignada. Por ejemplo, algo tan común como seleccionar todos los elementos que tengan la clase 'example' requería:

  • Seleccionar todos los elementos de la página con getElementsByTagName('*')
  • Iterar sobre los elementos comparando sus clases con la clase que buscamos
  • Tener en cuenta que puede haber una lista de clases separadas por espacios

La cosa se complica mucho si queremos buscar algo más complejo, como todos los elementos con clase 'example' que son hijos de un elemento ul con clase 'offer'.

jQuery ha abstraido toda esta complejidad del API del DOM en una fachada de uso simple e intuitivo: $("selector"). Podemos escribir simplemente:


$('.example')

$('ul.offer .example')

El uso es sencillo y elegante. De echo, el excelente diseño de las fachadas que proporciona jQuery es la razón principal de su éxito.

El excelente diseño de las fachadas que proporciona jQuery es la razón principal de su éxito

Como comentamos antes, también puede utilizarse para desacoplar un subsistema/componente/librería que utilizamos, reduciendo nuestra dependencia. En este caso se crea la fachada como un intermediario. Nuestro sistema realiza todas las llamadas a nuestra fachada y es la fachada la única que utiliza el componente específico.

De esta forma, si en el futuro dedicimos utilizar otro componente que provea esa funcionalidad, sólo tenemos que cambiar la parte de nuestra fachada que interactua con él. El interfaz que se ofrece hacia nuestro sistema no se modifica. De hecho, el sistema no necesita conocer nada del componente, sólo conoce el API que ofrece la fachada.



jueves, 25 de septiembre de 2014

Diferencia entre librería y framework

Una entrada corta para aclarar un par de conceptos que parece que mucha gente confunde: librería (o biblioteca) y framework.

He encontrado en multitud de sitios referencias a jQuery como un framework y esto es un error, jQuery es una librería. Por si tenemos alguna duda, en la própia página de jQuery nos lo aclaran:

What is jQuery?
jQuery is a fast, small, and feature-rich JavaScript library.

Una librería normalmente proporciona una serie de funciones/métodos muy concretos para simplificar tareas complejas. Podemos utilizarlas desde nuestro código respetando el API que proporcionan pero sin necesidad de adaptar/modificar nuestra estructura de aplicación.

Un ejemplo podría ser una librería matemática que ofrezca funciones avanzadas para cálculos estadísticos. JQuery es otro ejemplo, es una librería que proporciona funciones sencillas para manejo del DOM, para comunicación AJAX y algunas otras utilidades.

Un framework aporta una estructura completa en la que nosotros "encajamos" nuestro código, implementando la lógica concreta de la aplicación. Es mucho más que una librería. Impone unas condiciones a nuestra aplicación e incluso puede definir su arquitectura. Es un marco (framework) en el que nosotros vamos a definir piezas. El marco define las reglas del juego a las que nos tenemos que atener.

Un ejemplo serían los frameworks MVC (o MV*). La mayoría definen la forma en que tenemos que estructurar nuestra aplicación y la forma en la que los elementos de esta estructura se comunican. Deberemos crear modulos, modelos, vistas, etc, siguiendo unos patrones concretos y escuchar eventos predefinidos que marcan el flujo global en el que debe integrarse nuestra aplicación.

A veces un framework condiciona sólo una parte de nuestro programa, por ejemplo la parte gráfica en el caso de Bootstrap.

Simplificando mucho podríamos decir que nuestro código llama a las funciones de una librería mientras que un framework llamará a nuestro código, que sería algo así como piezas integradas en su estructura.

En una librería tu código es el que está al mando y utiliza las funciones de la librería cuando y como quiere. En un framework, éste es el que está al mando y tu código debe encajarse en su estructura y normas.

En cierto modo la diferencia principal es que un framework implica una forma de inversión de control porque nuestro código será invocado por él, que actua como coordinador de la actividad de nuestro programa.

martes, 24 de junio de 2014

JavaScript: Simular 'click' en un enlace <a>

Podemos utilizar la función trigger() de jQuery para lanzar un evento desde javascript:


$("#myButton").trigger("click");

Sin embargo no funcionará como esperamos si lo lanzamos sobre un link (elemento <a>). No nos llevará a la dirección del enlace.

Supongamos que tenemos el siguiente link para llevarnos a nuestra página de inicio:


Inicio

Despues nos piden que otro elemento de la página nos lleve al mismo sitio. Se nos ocurre la solución rápida de capturar el click en el nuevo elemento y lanzar un click al <a> con jQuery trigger().


//disparamos un click en el enlace para navegar a 'home.html'
//(NO FUNCIONARÁ)

$("#home-link").trigger("click");

No funciona porque lo que trigger() hace es disparar los event handlers asociados al evento, pero no seguirá el link, no navegará a la url.

En realidad trigger() dispara también el evento nativo, pero este es uno de los casos en los que tenemos que tener en cuenta que, como se explica en la documentación, no replica exactamente el evento real que originaría el usuario:

Although .trigger() simulates an event activation, complete with a synthesized event object, it does not perfectly replicate a naturally-occurring event.

La solución es disparar el evento con javascript puro (no jQuery). Primero obtenemos el elemento DOM (no jQuery) y luego utilizamos el método .click() nativo de los nodos del DOM:


document.getElementById("home-link").click();

También podemos utilizar el método .get() para obtener un elemento DOM a partir de un objeto jQuery:


$("#home-link").get(0).click();

Fuentes:

Learn jQuery: Triggering Event Handlers
StackOverflow: Why jquery cannot trigger native click on an anchor tag

lunes, 26 de mayo de 2014

CSS hover puede crear problemas en ipad

En el iPad y en el iPhone (en dispositivos táctiles iOS en general) nos encontramos a veces un comportamiento extraño: tocamos un link pero no nos lleva a la URL correspondiente, tocamos una segunda vez y entonces funciona.

En el primer toque se comporta como si fuera un hover, en el segundo como un click. El mapeo automático de click a touch parece no funcionar correctamente ¿de que depende? ¿porqué algunos links funcionan y otros no?

:hover en dispositivos táctiles

En un dispositivo táctil el concepto de hover no tiene sentido. No podemos colocar el cursor sobre un link, simplemento lo tocamos o no.

Parece lógico suponer que los dispositivos táctiles ignorarán el hover, pero no siempre es así. Los desarrolladores de Apple consideran que si se ha definido un comportamiento mediante CSS :hover puede haber información importante asociada y debe mostrarse. El primer toque funcionará como un hover y el segundo como un click.

En realidad iOS sólamente considera el comportamiento asociado a hover cuando modifica la visibilidad de un elemento de la página (visibility o display). Cualquier otra propiedad que cambiemos no tiene este efecto, los links responderán con un solo toque.

Este comportamiento realmente tiene sentido porque hay menús desplegables que se muestran al pasar el ratón por encima. iOS permite de esta manera que el primer touch muestre el submenú desplegable (hover) para despues hacer click en lo opción del submenu.

Si se muestran elementos nuevos en el hover, el primer click se considera una activación del nuevo contenido.

Este comportamiento está documentado en la iOS developer library:

"Si el usuario toca un elemento clickable, los eventos llegarán en este orden: mouseover, mousemove, mousedown, mouseup, and click. [...] Si el contenido de la página cambia en el evento mousemove, no se envía ninguno de los eventos posteriores. Este comportamiento permite al usuario pulsar en el contenido nuevo"

Se resume en la siguiente imagen:

El click funcionará con un sólo toque si no mostramos elementos nuevos. Por ejemplo, el siguiente CSS no supone ningún problema:

a:hover {
    color: blue;
}

Sin embargo es muy común mostrar un tooltip en el hover sobre un botón o un enlace. Cada vez que hagamos esto, ese botón necesitará dos toques en iOS para funcionar adecuadamente.

Solución para evitar el doble click

Lo primero que tenemos que considerar es que este comportamiento no es igual en todos los dispositivos táctiles, por eso debemos evitar mostrar elementos importantes en el hover.

Si utilizamos Modernizr podemos aprovechar la clase CSS 'no-touch' que crea para los dispositivos no táctiles:

    .no-touch p:hover span {
        display: block;
    }

De esta forma el span con nuestro tooltip se mostrará sólo en dispositivos no táctiles.

Otra solución es evitar el mapeo automático de touch a click y manejar explicitamente el evento touchstart junto con el click. Tendríamos el siguiente JS:

    ('#myElement').on( 'touchstart click', myClickCallback );

En vez de:

    ('#myElement').on( 'click', myClickCallback );



Fuentes:
jQuery click events on the iPad
stackOverflow: Javascript Events are not working in Tablet-pc
Fixing jQuery Click Events for the iPad
iOS has a :hover problem

jueves, 15 de mayo de 2014

Redirecciones en JavaScript

En JavaScript utilizamos el objeto Location, accesible desde la propiedad window.location, para obtener información y modificar la URL de la página actual.

Podemos hacer una redirección de varias maneras:

//la forma más habitual y recomendada
window.location.href = "http://google.com";

//Equivalente a la anterior. Es simplemente un atajo sintáctico
window.location = "http://google.com";

//Equivalente a las anteriores pero con formato 'método'
window.location.assign("http://google.com");

//Equivalente a una redirección HTTP. El botón 'back' no volverá a la pg actual
window.location.replace("http://google.com");
  

Lo más sencillo y corto sería utilizar el atajo sintáctico:

window.location = "http://google.com";

Aunque lo que se recomienda generalmente, por expresar mejor lo que hace, es:

window.location.href = "http://google.com";

La diferencia de location.replace("url") con las demás es que que sustituye la URL actual en el historial del navegador. Esto implica que al pulsar el botón back o hacer window.history.back() no volvemos a la página original, que ya no existe en el historial, sino a la anterior.

En resumen, podríamos decir que para simular un click en un link (cambiamos debido a una acción del usuario) utilizamos:

window.location.href = "http://google.com";

o sus equivalentes.

Para simular una redirección utilizamos:

window.location.replace( "http://google.com" );

Esta última es la que debemos usar cuando la página redirecciona automáticamente, para evitar el problema del bucle al pulsar back desde la página final, que nos lleva a la página anterior que nos vuelve a redireccionar a la final, y asi ad infinitum.

¿cual es la diferencia entre document.location y window.location?

En los navegadores actuales no hay diferencia, document.location se mapea a window.location y se cumple:

    document.location === window.location //true

NOTA: document.location era originalmente una propiedad de 'solo lectura' que devolvía la URL actual como un string en vez de un objeto Location.

¿Se ejecuta el javaScript en lineas posteriores a la redirección?

Aunque parezca poco intuitivo, si tenemos alguna línea de código despues de la asignación de window.location, sí se ejecutará. Por ejemplo, en el siguiente código:

    window.location.href = "http://google.com";
    window.location.href = "http://yahoo.com";
    alert( "test" );

La página final será yahoo.com, no google.com, y el alert aparecerá antes de redireccionarnos.

El script en curso continuará ejecutándose hasta el final, cuando devolverá el control al navegador para iniciar la carga de la nueva página. El navegador disparará entonces los eventos 'beforeunload' y 'unload'. En este momento la página original ya queda inactiva. El comportamiento puede ser inconsistente entre navegadores.

Fuentes:
StackOverflow
MDN - window.location


martes, 15 de abril de 2014

CSS Float: Tutorial Visual (II)

En la primera parte de este tutorial vimos los conceptos básicos de la propiedad float, ejemplos de cómo se comportan los elementos flotantes y cómo afectan a su entorno en el documento. Vamos a continuar viendo, también a través de ejemplos, cómo podemos modificar ese comportamiento.

Clear: Para no estar al lado de un float

Como ya hemos visto,  un elemento flotante modifica el comportamiento de otros elementos de bloque, que suben para ocupar su sitio y su contenido se desplaza para dejarle hueco . Este comportamiento se puede evitar con la propiedad clear, que puede tomas los valores: left, right, both, none o inherit.

Clear se aplica a elementos de bloque no flotantes o a cualquier elemento flotante, forzándolos a desplazarse debajo de un float anterior. Los valores indican a que lado del elemento no permitimos que haya un float: a la derecha, a la izquierda o a ambos.

Clear se aplica a elementos de bloque no flotantes o a cualquier elemento flotante, forzándolos a mostrarse debajo de un float

Vamos a retomar algunos ejemplos y aplicar clear para ver cómo afecta al resultado.
En la siguiente imagen tenemos 3 bloques con dimensiones diferentes y con float:left:

Los tres bloques con float:left

Si no queremos que el bloque azul se quede donde está, podemos ponerle clear:left. Con esto estamos indicando que este bloque no puede tener ningún float a su izquierda. Si hubiera alguno debe bajar hasta colocarse debajo. Y esto es lo que hace:

div#azul {
clear: left;
}

Bloque azul clear:left


Si en vez de eso aplicamos clear:left sólo al naranja:

div#naranja {
clear: left;
}


Bloque naranja clear:left

El naranja baja, porque no puede tener a su izquierda ningún bloque flotante y el azul se coloca a su lado. Si al bloque naranja le ponemos clear:both significa que no puede tener ningún elemento flotante a su izquierda ni a su derecha, pero si lo aplicamos veremos que no ocurre nada. Este ejemplo nos sirve para resaltar que la propiedad clear obliga a un elemento a colocarse debajo de un float anterior. Como el bloque azul está declarado despues en el HTML, no cambia nada.
Para desplazar el bloque azul podemos añadirle también clear:left:

div#naranja {
clear: left;

div#azul {
clear: left;
}
Bloque naranja y bloque azul con clear:left

Cuando tratamos con elementos no flotantes, la propiedad se aplica sólo a bloques, los elementos de línea no se ven afectados. En este ejemplo tenemos tres imágenes, el pez azul es flotante a la izquierda:

Pez azul float:left

Podriamos pensar que si le ponemos a la mariquita clear:left bajará a la siguiente línea, pero no es así, al ponerlo no cambia nada porque es un elemento de línea y no es flotante. Sin embargo, si tenemos imágenes dentro de bloques, sí podemos utilizarlo. En el siguiente ejemplo teníamos el pez azul con float:left y las otras dos imágenes en un div con borde rojo. El div ha subido al ser flotante la imagen del pez azul y las dos imágenes se han desplazado para dejarle sitio.


Pez azul con float:left. Las otras dos imágenes en un bloque

Si ahora le ponemos al div con borde rojo clear:left:

pez float:left, div con imágenes clear:left
El bloque no puede tener un float a su izquierda por lo que se desplaza abajo.

La propiedad clear es muy útil también para controlar como se coloca el texto alrededor de una imagen. En el siguiente ejemplo tenemos una imagen flotante a la izquierda y dos parrafos que hemos marcado con borde rojo:

imagen con float:left

Si no queremos que el segundo párrafo empiece a la derecha de la imagen le ponemos clear:left:

Imagen float:left, segundo párrafo con clear:left

Todo el bloque del párrafo baja para colocarse debajo del elemento flotante.
Si tenemos varias imágenes podemos utilizar clear para controlar cómo se colocan. En el siguiente ejemplo tenemos tres imágenes y a continuación 2 párrafos con el borde marcado en rojo. Ninguno es flotante:



Como queremos que el texto quede alrededor de las imágenes, vamos a hacerlas flotantes a la derecha, las tres ( float:right ). El resultado es:

Ejemplo con las imágenes flotantes a la derecha

Si queremos que el corazón quede debajo del caballo, le ponemos clear: right:

Las tres imágenes float:right, Corazón clear:right

Como el corazón no puede tener ningún elemento flotante a su derecha, bajará para colocarse por debajo. El periódico, que es flotante a la derecha, como los otras imágenes, quedará al lado del corazón, y no del caballo porque los elementos flotantes se desplazan a derecha o izquierda en su línea. El corazón a bajado y, para el periódico, declarado en el HTML después del corazón, esta es ahora su linea.

Es muy importante tener en cuenta que para lograr la disposición que queramos tenemos que jugar con float/clear y con el orden en que declaramos los elementos en el HTML. Si queremos que el periódico quede al lado del caballo y el corazón debajo, tenemos que cambiar el orden de las imágenes en el HTML. Ponemos primero el caballo, después el periódico y después el corazón. Las tres imágenes con float:right y el corazón, ademas con clear:right. Nos quedaría:

Las tres imágenes float:right. Corazón clear:right


Igualmente, si queremos que el primer párrafo quede por encima de las imágenes, tendría que estar declarado antes.

Es muy importante tener en cuenta que para lograr la disposición que queramos tenemos que jugar con float/clear y con el orden en que declaramos los elementos en el HTML

Para que las tres imágenes queden en vertical tendríamos que poner clear:right a la segunda y la tercera:

Las tres imágenes con float:right. Periódico y corazón con clear:right

Y este es un buen punto para retomar la explicación de los elementos contenedores que se encogen sin tener en cuenta los floats…


El contenedor menguante


La razón por la que el bloque contenedor se va encogiendo es sencilla: para los elementos de bloque (como el div contenedor) los elementos con float no ocupan espacio en la página, por lo tanto no los tiene en cuenta. En alguno de los ejemplos que hemos visto, con todos los elementos flotantes, el bloque no contiene nada. La única razón por la que no desaparece completamente es que tiene un padding declarado de 10px.

Este comportamiento a veces no es lo que queremos (ya veremos como se evita) y puede parecer un bug, un error de diseño, pero no lo es. Es una decisión consciente de los desarrolladores del estándar CSS y tiene una razón de ser: el texto que fluye alrededor de las imágenes flotadas.

Para entenderlo nos sirve un ejemplo similar al del apartado anterior. El siguiente documento tiene dos párrafos, y el primero de ellos contiene también una imagen:

Imagen y texto, ninguno flotante

Si hacemos la imagen flotante a la izquierda, todo queda como debe, el texto se coloca alrededor de la imagen como en los medios impresos tradicionales:

Imagen con float:left

Cada párrafo es un elemento de bloque que ha subido para recolocarse como si el float no estuviera ahí. El contenido de los bloques, al ser elementos de línea que quedan al lado de un float, acortan su longitud para dejarle sitio. El pez azul está dentro del párrafo 1, pero éste no le tiene en cuenta y se ha encogido hasta encerrar sólo al texto. Si el contenedor no ignorara al elemento flotante el resultado sería este:


Soluciones al problema del contenedor

Vamos a partir de un ejemplo con una imagen y un bloque de texto, los dos dentro de un div contenedor (#wrapper) que hemos marcado con borde negro.
Ponemos la imagen flotante a la izquierda y el bloque de texto flotante a la derecha. El texto está dentro de un div al que hemos puesto borde rojo y al que hemos fijado una anchura de 365 pixels para que quepa al lado de la imagen. Estos serían los estilos aplicados a cada elemento:

div#wrapper {
   padding: 10px;
   width: 500px;
   border: 1px solid black;
}

img {
   float:left;
}

div#texto {
   float:right;
   border: 1px dotted red;
   width: 365px;
}

El resultado visual es:

imagen float:left, bloque de texto float:right

Como el texto y la imagen son flotantes, el contenedor no los tiene en cuenta y queda vacío. No desaparece por completo porque tiene un padding de 10px. Hay varias formas de solucionar esto, vamos a ir viéndolas una por una.

1.-Hacer el contenedor flotante

Si el contenedor es también flotante sí abarcará a los elementos flotantes dentro de él. Si le ponemos, por ejemplo, float:right :

Contenedor con float:right
Naturalmente esta solución no siempre puede aplicarse, porque muchas veces necesitamos que el contenedor no sea flotante. Si lo tenemos centrado en la página, por ejemplo, al ponerlo flotante se nos desplazará estropeándonos el diseño. Afortunadamente hay más soluciones.

2.- Poner un elemento con clear después de los flotantes

Esta solución es muy utilizada porque no tiene ‘efectos secundarios’. Si tenemos un elemento de bloque después de los flotantes es perfecto, le ponemos clear:both  y el contenedor, al tener que contener a este elemento, incluirá también a los que están por encima (los flotantes). Recuerda que clear se aplica a elementos de bloque.
Cuando no tenemos ningún elemento más, como en nuestro ejemplo, tenemos que incluir uno vacío, normalmente un div,  sólo para ponerle el clear y arreglar el contenedor. Debajo del bloque que contiene el texto, añadiríamos el siguiente:

  <div class="clear"></div>

Definimos clear como una clase porque podemos utilizarla sobre otros elementos si los tenemos disponibles:

.clear {
clear: both;
}

Este div sería invisible, en la imagen de abajo le hemos puesto unos pixels de padding y borde verde para que se vea:

Div vacío con clear:both

El bloque contenedor se ha tenido que extender incluyendo a los float. El único problema de esta solución es que a veces tenemos que incluir elementos vacíos, que no tienen un significado real (semántico) en la página.

Para evitar esto actualmente se utiliza un pseudo elemento:

.clearfix:after {
 content: "";
 visibility: hidden;
 display: block;
 clear: both;
 height: 0;
 }

Esta clase se podría aplicar sobre el último elemento real, en este caso el párrafo, de forma que se aplica el clear sobre el pseudo elemento 'after' posterior.

3.- Utilizar la propiedad CSS  overflow

Si ponemos overflow:hidden o overflow:auto en el elemento padre (el contenedor en este caso) se expandirá siempre para abarcar a los elementos flotantes. Esta solución también es muy utilizada, sólo hay que tener en cuenta que esta propiedad implica también algo más, para saber si podemos aceptarlo:
overflow: hidden – Significa que el contenido que exceda de las dimensiones del div (si las tiene) se oculta, no habrá barra de desplazamiento ni se verán por fuera del div.
overflow: auto – Significa que si el contenido excede las dimensiones del div, aparecerán unas barras de desplazamiento para hacer scroll.
Algunos navegadores (IE6 por ejemplo) necesitan que el contenedor tenga fijada una anchura o altura para que la solución funcione bien.





sábado, 29 de marzo de 2014

CSS Float: Tutorial Visual (I)

Float es una propiedad CSS que define un tipo de posicionamiento de los elementos de una página web. En el estándar se definen tres esquemas de posicionamiento para presentar elementos:

  1. Normal.  (y aquí se incluye también el posicionamiento relativo).
  2. Absoluto.
  3. Flotante.

El flotante es, quizá, el menos intuitivo de los tres y el que presenta particularidades más ‘extrañas’ que intentaremos aclarar completamente en esta serie de dos totorales.

Conceptos Básicos

Para que un elemento flote utilizamos la propiedad float que puede tener los siguientes valores:

  • left – Flota a la izquierda
  • right – Flota a la derecha
  • none – No flota, valor por defecto
  • inherit – Hereda el valor del padre. No se utiliza porque en IE no funciona

Como vemos, un elemento no puede ser simplemente flotante, tiene que ser flotante a la derecha o flotante a la izquierda:

#elemento1 {
    float: right;
}
#elemento2 {
    float: left;
}

Que un elemento flote significa que intentará siempre desplazarse a la izquierda o a la derecha sobre la línea actual hasta chocar con el borde de su caja contenedora o de otro elemento flotante. Sólo otro elemento float puede interponerse entre él y el borde del contenedor. Veremos muchos ejemplos en los próximos apartados para entender todas las implicaciones de este comportamiento.

Hay cuatro reglas importantes que debemos tener en cuenta. Conociéndolas podremos siempre predecir dónde quedará un elemento si lo flotamos:

Reglas de los elementos float

  1. Los elementos por encima del float no se ven afectados, no cambian su posición.
  2. El elemento float se desplaza a derecha o izquierda hasta el borde de su contenedor o hasta chocar con otro elemento flotante.
  3. Los elementos de bloque se comportan como si el float no estuviera en la página, ocupando su hueco.
  4. Los elementos de línea, cuando quedan al lado de un float acortarán su longitud si es posible, para dejarle espacio.

Veremos también que este comportamiento se puede modificar con propiedades como clear o overflow.

Flotando elementos de bloque

Vamos a empezar viendo cómo se comportan los elementos de bloque (divs en este ejemplo) cuando los flotamos. Trabajaremos con un documento con tres divs, cada uno con un fondo de color diferente.

En el HTML simplemente hemos declarado el título y tres divs vacíos dentro de un div (#wrapper) que los envuelve a todos:

 <div id="wrapper">
  <h1>Sólo Bloques (Divs)</h1>
  <div id="verde"></div>
  <div id="naranja"></div>
  <div id="azul"></div>
 </div>

Por CSS les hemos puesto un borde punteado, altura, anchura y un color de fondo diferente a cada uno para que los ejemplos queden más claros

La página se verá así en pantalla:

Si asignamos float:right al bloque naranja se desplazará a la derecha y saldrá del flujo de elementos de la página para los otros elementos de bloque, que ocuparan su lugar como si no existiera:

¿Y si lo flotamos hacia la izquierda?

¿Qué ha pasado? Lo mismo que antes, el bloque flotante (naranja) sale del flujo de elementos de la página, los bloques que están debajo ocupan su lugar como si no existiera (el azul sube). El naranja se coloca en su línea hacia la izquierda hasta el borde del contenedor tapando el bloque azul.

Para los elementos de bloque, los float están fuera del flujo de elementos de la página, no ocupan espacio

¿Y si flotamos también el bloque azul?¿qué ocurrirá?

Como siempre, los bloques que están por encima no se ven afectados, el título (h1) y el bloque verde siguen en su sitio, pero por debajo nos llama la atención que el bloque contenedor (#wrapper) se ha encogido dejando fuera los dos bloques con float:left. La razón es sencilla, para los elementos de bloque (como el div contenedor, con borde negro en la imagen), los elementos flotantes no ocupan espacio en la página, por lo tanto no los tiene en cuenta. Veremos esto en detalle mas adelante y veremos también varias formas de evitarlo.

Para saber en que orden quedan los bloques es importante saber cómo están declarados en el código HTML. En este caso el naranja está primero, flota hacia la izquierda y sále del flujo de elementos, por lo que el azul sube a su misma línea, después éste también flota hacia la izquierda por lo que se intentará colocar al lado del borde o de otros elementos flotantes anteriores. En este caso le toca detrás del naranja.

Si flotamos también el verde el resultado es:

¿Y si flotamos también el título, al fin y al cabo es otro elemento de bloque (h1)?

Como el título es el primer elemento, flota en su línea a la izquierda, los demás elementos van subiendo y flotando en su misma línea detrás de él. Cuando no hay sitio en la misma línea se desplazan a la siguiente, donde hay hueco para seguir colocándose. Y mientras tanto, el div contenedor a lo suyo, encogiendo hasta casi desaparecer.

Cuando un elemento fotado cambia de línea por falta de espacio, es muy importante tener en cuenta la altura de las cajas de cada uno, porque el elemento se quedará donde tenga un hueco y puede quedar colocado de forma extraña:

En este caso el bloque azul no cabe al lado del naranja y se desplaza a la línea siguiente pero se ha quedado ‘enganchado’ en el verde porque es unos pixels más alto que el naranja. Al cambiar de línea quedará en el primer lugar que quepa, tocando al bloque de arriba. En este caso el problema se ve muy claro, pero cuando no tenemos fondos de color y un borde marcado, los elementos quedan descuadrados y el problema no se ve fácilmente.

La siguiente situación es parecida pero ahora el bloque azul es más ancho que la distancia que queda entre el verde y el borde del contenedor, como no cabe debajo del naranja, se irá hasta el extremo:


Elementos de Línea: Imágenes y Texto

Las líneas de texto, y cualquier elemento de línea en general (span, em, strong, etc), adaptarán su longitud al colocarse al lado de un elemento flotante, para dejarle hueco.

Vamos a empezar viendo como se comportan las imágenes, que actúan como elementos de línea aunque en realidad son una mezcla, inline-block, porque fluyen en la línea pero tienen altura y anchura definible con width y height.

Veamos un documento con tres imágenes:

¿Qué ocurrirá si flotamos el pez azul hacia la izquierda?

img#pezAzul {
    float:left;
}

El pez azul se desplazará alegremente en su línea hacia la izquierda hasta el borde del contenedor (o hasta chocar con otro elemento flotante, pero en este caso no hay ninguno) y los otros elementos de línea (las otras dos imágenes), al estar al lado de un float, le harán hueco:

Si lo flotamos a la derecha:

La imagen se desplaza a la derecha hasta el borde y los otros elementos le dejan hueco.

¿Y si las imágenes estuvieran dentro de bloques, en un div? Para saber cómo van a quedar los elementos es importante saber en que orden están declarados en el código. Declaramos primero un título, luego la imagen del pez, y luego un div con borde rojo que contiene dos imágenes, la mariquita y el smiley:

 <h1>Imágenes en Divs</h1>
 <img src="images/fish1.png">
 <div class="bordeRojo">
  <img src="images/bug.png">
  <img src="images/smile.png">
 </div>

Las dos imágenes de abajo están contenidas en un div, que es un elemento de bloque y ocupa su propia línea.

Si ahora flotamos la imagen del pez hacia la izquierda:

Lo que ocurre es lo siguiente:

  1. La imagen sále del flujo normal de elementos de la página por lo que no ocupa espacio (para los elementos de bloque)
  2. El bloque de abajo (con borde rojo) sube para ocupar su espacio
  3. Los elementos de línea (las 2 imágenes) se encuentran ahora al lado de un float y se desplazan para hacerle hueco

Este comportamiento se ve mucho más claro con las líneas de texto, que también son elementos de línea (faltaría mas) y normalmente están contenidas dentro de un párrafo (<p>…</p>) que es un elemento de bloque.

En el siguiente ejemplo tenemos un documento con un título, una imagen y un párrafo:

Si flotamos la imagen a la izquierda el bloque de texto subirá como si la imagen no existiera. Las líneas quedan ahora al lado de un float y se acortarán para fluir por el lado de la imagen:

Si la flotamos a la derecha:


Terminando por hoy …

Aqui vamos a terminar la primera entrega de este tutorial, en la segunda parte veremos:

  • El uso de la propiedad clear, con numerosos ejemplos para ver cómo afecta a elementos de bloque y de línea, dependiendo de si son flotantes o no y cómo podemos utilizarlo para controlar la disposición de los elementos.
  • Porqué se produce el ‘problema’ del contenedor, que se encoge hasta desaparecer cuando contiene elementos flotantes. Veremos que esto no es un error, sino una decisión de diseño. Sabremos el porqué y varias formas diferentes de evitarlo.
  • Cómo utilizar los floats para diseñar la estructura de una página.

viernes, 7 de marzo de 2014

Atributos 'defer' y 'async' en <script>

Cuando incluimos un script en una página mediante las etiquetas <script></script>, éste se cargará de forma síncrona bloqueando el resto de la página hasta que se haya ejecutado. Ocurre lo mismo tanto si el código es inline como si es un archivo remoto. En la entrada "Los scripts externos pueden bloquear tu web" explicaba en detalle las diferencias entre carga síncrona (bloqueante) y carga asíncrona (no bloqueante).

Aunque la presentación está bloqueada, los navegadores modernos buscan otros ficheros externos que tengan que cargar y lanzan la petición (js, imágenes, css). La descarga sí se inicia, pero toda la presentación de elementos está bloqueada hasta que se ejecuten. Por esto se recomienda colocar los scripts al final, para que todo el HTML se haya presentado ya en pantalla y el usuario tenga una sensación de carga rápida.

Hay dos atributos que podemos incluir en la etiqueta <script> para modificar este comportamiento y forzar la carga asíncrona (no bloqueante):

  • defer <script defer src="myFile.js"></script>
  • async (HTML5) <script async src="myFile.js"></script>

Los dos son atributos booleanos y tienen un funcionamiento similar. La diferencia principal es el momento en que se ejecuta el código descargado. En el caso de async se ejecuta en cuanto la descarga se ha completado, mientras que en el caso de defer se ejecuta cuando se ha terminado de parsear toda la página.

Atributo 'defer'

Microsoft introdujo defer en el Internet Explorer 4 para evitar que los scripts bloquearan la presentación del resto de la página si no era necesario (si no incluian elementos nuevos).

Se utiliza de la siguiente manera:

    
<script defer src="myFile.js"></script>

Se estandarizó en HTML4 con el siguiente texto:

"defer
Este atributo booleano proporciona una indicación para el UA [browser] de que el script no va a generar ningún contenido en el documento (p.ej. el javascript no contiene document.write) y, por lo tanto, el UA puede continuar con el parseo y presentación"

En HTML5 se especifica de la siguiente forma:

async y defer son atributos booleanos que indican cómo se deben ejecutar los scripts. Los atributos defer y async no deben especificarse si no existe el atributo src.

[...]si el atributo defer está presente [sin el atributo sync] el script se ejecuta cuando la página se ha terminado de parsear.

Es decir, este atributo se utiliza únicamente para scripts externos, se ignora para scripts inline. Algunas versiones de IE (IE<10) no respetan esta indicación del estandar y pueden aplicar defer a código en línea.

Los scripts se ejecutan justo antes de lanzarse el evento DOMContentLoaded.

Además, en otro punto del estandar se indica que los scripts con defer deben ejecutarse en el orden en que se especificaron en la página.

Atributo 'async'

async se introduce en HTML5 para indicar que el script debe cargarse de forma asíncrona, sin bloquear la presentación del resto de contenido, y ejecutarse inmediatamente cuando se haya descargado. El orden de ejecución no se garantiza.

    
<script async src="myFile.js"></script>

La especificación de HTML5 indica lo siguiente:

async y defer son atributos booleanos que indican cómo se deben ejecutar los scripts. Los atributos defer y async no deben especificarse si no existe el atributo src.

[...] Si el atributo async está presente el script se ejecuta de forma asincrona tan pronto como esté disponible.

En este caso el evento DOMContentLoaded también esperará a que el script se ejecute.

Los dos juntos: 'async' + 'defer'

Cuando los dos atributos aparecen juntos, async prevalece sobre defer si el navegador lo soporta. defer puede añadirse como fallback para navegadores antiguos:

El atributo defer puede especificarse incluso si el atributo async está presente, para que los navegadores antiguos que sólo soportan defer utilicen esa opción en vez de la descarga síncrona bloqueante que sería la opción por defecto.

Debido a las diferentes implementaciones es mejor evitar dependencias y no asumir, en ningún caso, que los scripts se ejecutarán en orden ( con defer). Evitaremos problemas si consideramos siempre que se descargarán de forma asíncrona pero no se garantiza el orden de ejecución.

Inyectando un <script> dinámicamente

Otra opción muy usada para cargar un script de forma asíncrona es inyectar la etiqueta <script> dinámicamente, con javascript:

    

var script = document.createElement("script");
script.src = "/path/to/script.js";
document.getElementsByTagName("head")[0].appendChild(script);

Los <script> que se añaden dinámicamente al documento son asíncronos por defecto, no bloquean la presentación de la página y se ejecutan en cuanto se han descargado. El mismo comportamiento que con el atributo async.

En este caso el evento DOMContentLoaded no espera a que el script se haya ejecutado.

A veces podemos encontrar también que se incluye el atributo *async* en este tipo de scripts:

var script = document.createElement("script");
script.src = "/path/to/script.js";    
script.async = true;               //set async attribute 
document.getElementsByTagName("head")[0].appendChild(script);

Es únicamente para los navegadores Firefox 3.6 y Opera, que no tienen el comportamiento asíncrono por defecto para *scripts* inyectados pero soportarn el atributo *async*.

Fuentes:

W3C HTML5 Scripting
HTML: The Markup Language (an HTML language reference)
Deep dive into the murky waters of script loading

sábado, 1 de febrero de 2014

Atributos booleanos en HTML

En el estándar de HTML del W3C se definen algunos atributos como booleanos. Puede resultar confuso porque, a pesar de su nombre, no admiten los valores true o false. Ejemplos de estos atributos son: checked, disabled, defer, selected, etc.

En este tipo de atributos, su presencia en el elemento representa el valor true y su ausencia false. Por ejemplo, en el siguiente HTML, el primer checkbox estaría seleccionado (checked) y el segundo no:

<input type="checkbox" name="vehicle" value="car" checked>

<input type="checkbox" name="vehicle" value="plane">

Si el atributo está presente puede asignarsele un valor, aunque no es necesario. Los únicos valores admitidos son: un string vacío o un string con el mismo nombre del atributo.


Los valores true y false están especificamente prohibidos en los atributos booleanos. Para representar el valor false el atributo no debe aparecer.

En el siguiente ejemplo podemos ver varios checkbox con los atributos checked y disabled con y sin valor asignado. Todos los casos son correctos y equivalentes.

<input type="checkbox" name="vehicle" value="car" checked disabled>

<input type="checkbox" name="vehicle" value="car" checked="checked" disabled="disabled">

<input type="checkbox" name="vehicle" value="car" checked disabled="">

Atributos booleanos y javaScript

El hecho de que estos atributos no tengan un valor (o puedan no tenerlo), supone un pequeño cambio respecto a la manipulación habitual de atributos que hacemos en javaScript. No podemos modificar/leer el valor del atributo para conseguir un comportamiento u otro, como haríamos normalmente con la función .attr() de jQuery o con getAttribute()/setAttribute() de javaScript. Lo que tenemos que detectar es si el atributo está presente o no, su valor no es importante.

En realidad, para los atributos booleanos, lo que debemos leer es la propiedad equivalente del elemento en el DOM, no el atributo. JavaScript nos permite acceder a los dos. El atributo es lo que se ha indicado en el código HTML, mientras que la propiedad contiene el valor real, en cada momento, de 'atributos' y otros valores del elemento en el DOM. Las propiedades correspondientes a atributos booleanos tienen valores true o false. Esto sí son realmente booleanos.


En el caso de atributos booleanos, los atributos tendrán el valor inicial que se asignó en HTML, independientemente de que el usuario lo modifique despues (desmarcando un checkbox, por ejemplo). La propiedad siempre nos da el valor real.


Si tenemos el siguiente código HTML:

<input type=checkbox name="test" value="a" checked>A
<input type=checkbox name="test" value="b">B

Que nos mostraría lo siguiente:

En lo siguientes ejemplos podemos ver cómo leemos el valor del atributo y de la propiedad checked en jQuery y en JavaScript. Como comentario al lado, aparece el resultado que obtenemos:

//leyendo los atributos con jQuery
$("input").eq(0).attr("checked"); //checked
$("input").eq(1).attr("checked"); //undefined

//leyendo las propiedades con jQuery
$("input").eq(0).prop("checked"); //true
$("input").eq(1).prop("checked"); //false

//leyendo los atributos con javaScript
document.getElementsByTagName("input")[0].getAttribute("checked"); //""
document.getElementsByTagName("input")[1].getAttribute("checked"); //null

// ..también podemos usar .hasAttribute() en IE8+
document.getElementsByTagName("input")[0].hasAttribute("checked"); //true
document.getElementsByTagName("input")[1].hasAttribute("checked"); //false

//leyendo las propiedades con javaScript
document.getElementsByTagName("input")[0].checked; //true
document.getElementsByTagName("input")[1].checked; //false

Lo correcto es leer la propiedad, porque el atributo no refleja los cambios que puede haber hecho el usuario (depende del navegador).

Para asignar checked a un elemento mediante jQuery/javaScript podemos hacer lo siguiente:

//Asignar/eliminar la propiedad con jQuery
$("input").eq(1).prop("checked", true);
$("input").eq(1).prop("checked", false);

//Asignar/eliminar el atributo con jQuery
$("input").eq(1).attr("checked","");
$("input").eq(1).removeAttr("checked");

//Asignar/elminar la propiedad con javaScript
document.getElementsByTagName("input")[1].checked = true;
document.getElementsByTagName("input")[1].checked = false;

//Asignar/eliminar el atributo con javaScript
document.getElementsByTagName("input")[1].setAttribute("checked");
document.getElementsByTagName("input")[1].removeAttribute("checked");

Aunque cambiar el atributo con javaScript (o jQuery) sí se refleja en la propiedad correspondiente, es mejor manejar siempre la propiedad como hacemos al leerlo.

Conclusión

Lo más importante que tenemos que tener en cuenta es que el atributo y la propiedad son dos cosas diferentes que no siempre están sincronizadas. El atributo no cambia para reflejar el estado del elemento, la propiedad si.

En el caso concreto de 'checked', el atributo no se corresponde con la propiedad 'checked', sino con 'defaultChecked', que indica el valor inicial definido.

Al leer los atributos booleanos con javaScript, el atributo nos da el valor inicial, fijado en el código HTML, no responde a los cambios de estado del elemento. Debemos leer la propiedad checked.

Al modificar el estado del atributo con javaScript sí hay una sincronización atributo-propiedad, podríamos hacerlo de las dos formas pero es recomendable utilizar siempre la propiead.



sábado, 11 de enero de 2014

Tutorial de @font-face

La regla @font-face de CSS nos permite incluir en una página web tipografías diferentes de las instaladas en el PC del usuario. Es decir, nos da la libertad de incluir cualquier fuente en nuestro diseño y enviarsela al usuario como parte de la página web que está viendo.

Uso básico

Si quisieramos utilizar la fuente "shattered.ttf" que tenemos en nuestro servidor, podríamos incluirla de la siguiente forma:

@font-face {
    font-family: myFontName;    //aqui podemos usar cualquier nombre
    src: url('fonts/shattered.ttf') format("truetype");
}

Este es el uso más básico. Incluimos la fuente sólo en un formato y le damos un nombre para utilizarla en nuestra applicación. El nombre que ponemos en font-family puede ser cualquiera, no tiene que coincidir con el nombre real de la fuente. En este caso, cuando queramos usarla, la referenciamos como "myFontName".

La utilizaremos de la siguiente forma:

h1 {
    font-family: myFontName, Georgia, "Times New Roman", serif;
}

@font-face está soportado en todos los navegadores modernos (e incluso en IE6), pero no todos soportan el mismo formato de fuentes. Si queremos que nuestra letra se muestre en todos los navegadores, estamos obligados a tener los ficheros en varios formatos distintos.

Incluir varios formatos de fuente

Las incompatibilidades entre navegadores nos impiden utilizar una regla tan sencilla como la que hemos visto. Por un lado, IE<9 sólo admite el formato propio EOT, que no está soportado por ningún otro navegador. Algunos navegadores de móviles sólo admiten formato SVG, y luego tenemos los formatos TTF, OTF y WOFF. En el siguiente cuadro vemos los formatos diferentes que podemos incluir y el soporte que tienen:

@font-face file types browser support
  WOFF OTF TTF SVG EOT
IE 9 9 9 no 4
Firefox 3.6 3.5 3.5 no no
Opera 11.1 10 10 10 no
Opera Mobile 11.0 9.7 9.7 9.7 no
Safari 5.1 3.1 3.1 3.1 no
Chrome 6 4* 4* 0.3 no
Safari on iOS 5 no 4.2 3.1 no

Fuente: Stunning CSS3

Afortunadamente podemos utilizar el excelente servicio gratuito Font Squirrel para convertir nuestra letra en diferentes formatos e incluso generar el css necesario para utilizarlos.

Podemos incluir todos los formatos necesarios con la siguiente declaración, conocida como Fontspring Syntax o New Bulletproof Syntax:

@font-face {
    font-family: 'MyFontName';
    src: url('fonts/shattered.eot?#iefix') format('embedded-opentype'),
         url('fonts/shattered.woff') format('woff'),
         url('fonts/shattered.ttf')  format('truetype'),
         url('fonts/shattered.svg#svgFontName') format('svg');
}

La clave de esta declaración es un pequeño hack: incluir la interrogación despues del fichero EOT 'shattered.eot?#iefix'. La razón es que IE<9 no entiende múltiples urls separadas por comas, ni tampoco la indicación de formato format(). Considera que todo lo que aparece despues del paréntesis de apertura, hasta el último, es una URL.

Al incluir la interrogación, conseguimos que el IE entienda que la url es fonts/shattered.eot y considere el resto como parámetros de url que serán ignorados en el servidor. Es muy importante que el fichero EOT aparezca el primero.

Si queremos que IE>9 utilice el formato WOFF en vez de EOT, podemos hacer una pequeña variación cambiando el format del EOT a un valor incorrecto (el correcto es 'embedded-opentype'). De esta forma lo descartará y utilizará el siguiente que reconozca:

@font-face {
    font-family: 'MyFontName';
    src: url('fonts/shattered.eot?#iefix') format('eot'),
         url('fonts/shattered.woff') format('woff'),
         url('fonts/shattered.ttf')  format('truetype'),
         url('fonts/shattered.svg#svgFontName') format('svg');
}

Esta es la declaración más compacta, es compatible con todos los navegadores pero puede presentar algún problema con el IE9 cuando se utiliza en modo compatibilidad con IE7-8, como se explica aqui. Si nos interesa cubrir también esas opciones, podemos duplicar la src, incluyendo el fichero .eot de dos formas diferentes:

@font-face {
    font-family: 'MyFontName';
    src: url('fonts/shattered.eot'); /* IE9 Compat Modes */
    src: url('fonts/shattered.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
         url('fonts/shattered.woff') format('woff'), /* Modern Browsers */
         url('fonts/shattered.ttf')  format('truetype'), /* Safari, Android, iOS */
         url('fonts/shattered.svg#svgFontName') format('svg'); /* Legacy iOS */
    }

Cualquier navegador diferente del IE ignorará los ficheros .eot y saltará a la siguiente declaración hasta encontrar un formato que pueda usar.

Esta es una sintaxis universal, compatible con todos los navegadores en todos los casos.

Descartando fuentes locales con: local('☺')

Podemos encontrar también declaraciones incluyendo local('☺') con un smiley o cualquier otro caracter extraño:

@font-face {
    font-family: 'MyFontName';
    src: url('fonts/shattered.eot');
    src: local('☺'),
         url('fonts/shattered.woff') format('woff'),
         url('fonts/shattered.ttf')  format('truetype'),
         url('fonts/shattered.svg#svgFontName') format('svg');
}

El src: local() normalmente sirve para especificar una tipografía local (en el ordenador del usuario) que puede utilizarse sin tener que descargar ningún fichero. En este caso se incluye con un carácter especial (smiley) sólo para evitar que el navegador utilice una fuente local con el mismo nombre que la nuestra, si existe.

El problema con esto es que Android 2.2-2.3, aunque tienen soporte para @font-face, no soporta local(), con lo que nuestra declaración no funcionará para esos sistemas.

Definiendo cursiva, negrita, etc

La fuente que estamos utilizando puede tener versiones cursiva, negrita, etc:

shattered-regular.ttf
shattered-bold.ttf
shattered-italic.ttf

Para incluirlas primero tenemos que convertir todos los ficheros a los formatos necesarios. Despues tenemos dos posibilidades: incluirlas con nombre distinto (MyFontName, MyFontName-italic, etc) o incluirlas con el mismo nombre para utilizarlas con font-weight o font-style (Style Linking):

font-weight: bold;
o
font-style: italic;

La segunda solución es mejor, pero debemos tener en cuenta que no funciona en IE.

En cualquiera de los dos casos necesitaremos una declaración @font-face diferente para cada tipo.

Si las declaramos con diferente nombre:

/* Regular */
@font-face {
    font-family: 'MyFontName';
    src: url('fonts/shattered-regular.eot?#iefix') format('embedded-opentype'),
         url('fonts/shattered-regular.woff') format('woff'),
         url('fonts/shattered-regular.ttf')  format('truetype'),
         url('fonts/shattered-regular.svg#svgFontName') format('svg');
}

/* Bold */
@font-face {
    font-family: 'MyFontName-bold';
    src: url('fonts/shattered-bold.eot?#iefix') format('embedded-opentype'),
         url('fonts/shattered-bold.woff') format('woff'),
         url('fonts/shattered-bold.ttf')  format('truetype'),
         url('fonts/shattered-bold.svg#svgFontName') format('svg');
}

/* Italic */
@font-face {
    font-family: 'MyFontName-italic';
    src: url('fonts/shattered-italic.eot?#iefix') format('embedded-opentype'),
         url('fonts/shattered-italic.woff') format('woff'),
         url('fonts/shattered-italic.ttf')  format('truetype'),
         url('fonts/shattered-italic.svg#svgFontName') format('svg');
}

Tendríamos que utilizarla de la siguiente forma:

body { font-family: MyFontName, Georgia, serif; }
h1 { font-family: 'MyFontName-bold', Georgia, serif; }
em { font-family: 'MyFontName-italic', Georgia, serif; }

Si las declaramos con el mismo nombre, utilizando Style Linking:

/* Regular */
@font-face {
    font-family: 'MyFontName';
    font-style: normal;
    font-weight: normal;
    src: url('fonts/shattered-regular.eot?#iefix') format('embedded-opentype'),
         url('fonts/shattered-regular.woff') format('woff'),
         url('fonts/shattered-regular.ttf')  format('truetype'),
         url('fonts/shattered-regular.svg#svgFontName') format('svg');
}

/* Bold */
@font-face {
    font-family: 'MyFontName';
    font-style: normal;
    font-weight: bold;
    src: url('fonts/shattered-bold.eot?#iefix') format('embedded-opentype'),
         url('fonts/shattered-bold.woff') format('woff'),
         url('fonts/shattered-bold.ttf')  format('truetype'),
         url('fonts/shattered-bold.svg#svgFontName') format('svg');
}

/* Italic */
@font-face {
    font-family: 'MyFontName';
    font-style: italic;
    font-weight: normal;
    src: url('fonts/shattered-italic.eot?#iefix') format('embedded-opentype'),
         url('fonts/shattered-italic.woff') format('woff'),
         url('fonts/shattered-italic.ttf')  format('truetype'),
         url('fonts/shattered-italic.svg#svgFontName') format('svg');
}

NOTA: La fuente regular tiene que estar la primera.

Definiéndolo de esta manera, podemos utilizar la fuente con el mismo nombre y definirla como negrita o italica con font-weight o font-style:

body { font-family: shattered, Georgia, serif; }
h1 { font-weight: bold; }
em { font-style: italic; }

Fuentes:
Stunning CSS3: @font-face File Types Browser Support
Paul Irish: Bulletproof @font-face Syntax
Fontspring: The New Bulletproof @Font-Face Syntax
CSS Tricks: Using @font-face
Ksesocss: @Font-face y sus problemas. Guía de uso y solución de problemas
Especificación del W3C