domingo, 4 de noviembre de 2012

Hacer un mosaico/galería con HTML y CSS

Un mosaico o galería de imágenes es un elemento básico que utilizado en multitud de aplicaciones web:

galería de fotos de Picasa
Esta distribución de elementos es muy sencilla de realizar con HTML y CSS. Vamos a ver a continuación algunos ejemplos y algunas de las particularidades que nos podemos encontrar.

El ejemplo que vamos a hacer va a ser el siguiente:

Siempre vamos a tener un contenedor, que en la imagen anterior vemos con un borde punteado, dentro del cual que colocan los elementos.

Los elementos pueden ser cualquier cosa, desde una simple imagen, como en la galería de Picasa, hasta un div conteniendo textos, imágenes y otros div's interiores, como en la galería de películas de Youzee:


En nuestro ejemplo el elemento es un div con otro div interno, con los bordes redondeados hasta hacer un círculo, y un número. Como el contenido del elemento no es importante para este tutorial, simplemente lo representaremos como:

1


El HTML para nuestros 8 elementos sería:
1
2
3
4
5
6
7
8
No tiene ninguna dificultad, es un div contenedor envolviendo a los elementos que formarán la galería. También es muy común ver esta misma estructura con una lista <ul> como contenedor y los items <li> de la lista como elementos. Lo veremos más adelante.

Con lo que realmente construimos la galería es con el CSS:
#container {
  border: 1px dotted black;
  overflow: hidden;
  width: 450px;
}

.element {
  width: 100px;
  height: 150px;
  float: left;
  margin : 5px;
}


Lo más importante en estas pocas líneas de CSS es que los elementos tienen float: left. Esto es lo que hace que se coloquen como un mosaico. El hecho de que sean float nos obliga a poner overflow:hidden en el contenedor para que los envuelva y no se quede vacío (aunque hay otras soluciones ).

El margin de 5px de los elementos sirve para que no queden pegados y tengan esa pequeña separación entre ellos, tanto por arriba como a los lados.

También vemos que hemos dado una anchura fija al contenedor para que quepan justo cuatro elementos, pero no tiene que ser necesariamente así. Es una galería autoajustable y podemos dejarlo sin anchura fija para que ocupe todo el ancho disponible, los elementos se redistribuirán automáticamente:


Podemos fijar una anchura mínima y/o máxima para que se quede siempre dentro de unos márgenes aceptables para el diseño gráfico de nuestra aplicación:

#container {
  border: 1px dotted black;
  overflow: hidden;
  min-width: 230px;
  max-width: 700px;
}

Con los valores anteriores conseguimos que el diseño sea líquido pero que nunca se expanda más de seis columnas ( con sus respectivos márgenes ) o se contraiga hasta contener menos de dos columnas.

También podríamos utilizar display: inline-block para los elementos, pero presenta un pequeño inconveniente cuando tenemos que hacer diseños con unas especificaciones muy concretas (márgenes, dimensiones, etc). El problema es que dejan un pequeño margen extra entre elementos. Esto lo veremos más detalladamente en otra entrada.

Utilizando una lista

Como hemos comentado antes, se puede utilizar una lista para hacer la galería. Algunos programadores argumentan que el HTML resultante es más semántico, aunque tengo mis dudas sobre este punto.

El código es muy parecido al anterior. El HTML sería:
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
Y el CSS:
#container {
  border: 1px dotted black;
  overflow: hidden;
  width: 450px;
  padding: 0px;

}

.element {
  list-style: none;
  width: 100px;
  height: 150px;
  float: left;
  margin : 5px;
}

El CSS tiene dos novedades importantes. Primero tenemos que resetear el padding de nuestra lista <ul>, con el id #container, porque algunos navegadores fijan un padding izquierdo por defecto que haría que el mosaico quedara un poco desplazado a la derecha.

El segundo detalle a tener en cuenta es que tenemos que eliminar el 'disco' que normalmente tienen a la izquierda los elementos de una lista. Para esto hacemos list-style: none.

El resultado es el mismo que en el ejemplo anterior.

jueves, 1 de noviembre de 2012

¿Por qué se necesitan paréntesis para hacer eval() de JSON?

Como vimos en otra entrada, cuando recibimos un JSON tenemos que hacer que el motor de JavaScript lo interprete para convertir el string en objetos JavaScript nativos. Una forma de hacer esto ( poco recomendable, ver el tutorial ) es utilizar la función eval():

eval (‘(‘ + myJsonString + ‘)’ );

Como vemos en el ejemplo, para asegurarnos de que el código se evalúa correctamente es necesario añadir unos paréntesis que lo envuelvan. La razón es que cuando evaluamos cualquier string se lo estamos pasando al parser de JavaScript para que lo interprete. Cuando el parser encuentra una llave ‘{’ al principio de una instrucción lo interpreta como el inicio de un bloque, no como el inicio de un objeto.

Normalmente, en un código JavaScript, un objeto no aparece aislado, sino como parte de una expresión:

var test = { name: “Pepe”};

La llave no está al principio. Cuando se encuentra al principio el parser espera un bloque de instrucciones:

{
    var one = 1;
    var two = “dos”;
    myFunction();
}

Al esperar un conjunto de instrucciones y encontrarse con algo del tipo:


“clave1”:  valor1,
“clave2”:  valor2

lanzará un error. Es símplemente la forma en la que funciona el parser al interpretar un código JavaScript.

Para evitar que se tome como bloque y se evalúe correctamente, debemos hacer que el objeto forme parte de una expresión. Lo podemos conseguir simplemente encerrándolo entre paréntesis:


( { “name” : “Pepe”} )

Después de encontrar un paréntesis el parser evalúa la llave ‘{‘ como el comienzo de un objeto literal, que es lo que necesitamos.

viernes, 26 de octubre de 2012

Tutorial de JSON

JSON (JavaScript Object Notation) es un formato estándar para intercambio de datos que prácticamente ha sustituido a XML como el formato preferido para traspaso de datos entre cliente y servidor web.


Es una sintaxis estandarizada, un conjunto de reglas en el que nos hemos puesto de acuerdo para poder pasar información sabiendo como codificarla y decodificarla.

Se basa en la notación literal de JavaScript para estructurar datos en arrays y en objetos. Es una forma sencilla de 'empaquetar' información para enviarla:

{
"title": "The wonderful guide",
"pages": 348,
"price": 15
}

A pesar de llevar JavaScript integrado en el acrónimo, es un estándar independiente definido en la RFC 4627 y puede utilizarse en cualquier lenguaje.

El sustituto de XML

AJAX revolucionó la forma en la que se desarrollan aplicaciones web. En vez de pedir al servidor páginas completas cada vez que algo cambia, se pide sólo la información que ha cambiado. Es decir, se piden datos.

Se hizo necesario un formato para intercambio de datos, para enviarlos desde el servidor, que tiene la base de datos, al cliente que se encarga de presentarlos. El formato elegido fue, en principio, XML. Parecía tan apropiado que incluso forma parte de las siglas AJAX (Asynchronous Javascript And XML).

Douglas Crockford propuso, en el año 2001, JSON como una alternativa más ligera, sencilla y eficiente porque encontraba que XML no era muy apropiado para esta tarea. El nuevo formato se popularizó rápidamente y se ha convertido en el estándar de facto para este tipo de transferencias.

JSON es más sencillo de codificar y más facil de leer, pero probablemente el factor más importante para su éxito es que utiliza unas estructuras de datos que son nativas para JavaScript, el lenguaje del cliente (no olvidemos que es la 'J' de AJAX).

¿Cómo codifico datos en JSON?

Para enviar datos en JSON debemos organizarlos de alguna de estas dos formas:

  • Un conjunto de pares clave/valor entre llaves { clave1: valor1, clave2: valor2 } (un objeto en JavaScript)
  • Una lista de valores entre corchetes [valor1, valor2] (un array en JavaScript)

Sólo existen estas dos opciones, cualquier dato tiene que enviarse de esta forma (En realidad lo que se envía es un string con esta estructura).

Por ejemplo, supongamos que sacamos de la base de datos la información de un empleado: nombre, edad y cargo. Para enviarlo como JSON válido tendriamos que colocarlo con la siguiente estructura:

{
 "nombre": "Pepe",
 "edad": 22,
 "cargo": "botones"

}

También podríamos ponerlo en forma de array, pero en este caso tiene menos sentido:


["Pepe", 22, "botones"]

Lo que sí tiene sentido es utilizar un array para enviar los datos de varios empleados:

[
    {
      "nombre": "Pepe",
      "edad": 22,
      "cargo": "botones"
    },
    {
      "nombre": "Julio",
      "edad": 32,
      "cargo": "albañil"
    },
    {
      "nombre": "Tim O'Theo",
      "edad": 28,
      "cargo": "detective"
    }
]   

Objetos y arrays se pueden anidar hasta crear estructuras muy complejas.

Aunque tengamos un único dato debe enviarse tambien de esta forma, como un objeto de una sóla propiedad o un array de un sólo elemento:


["Pepe"]

o

{ "nombre": "Pepe"}

Como podemos ver en estos ejemplos, las claves de los pares clave/valor tienen que ir siempre entre comillas dobles.

Los valores pueden ser: objetos, arrays, números, strings, booleanos o null.

Usando JSON en JavaScript

No olvidemos que lo que se envía/recibe es siempre un string. Por eso cuando enviamos del cliente al servidor, aunque JavaScript ya tiene los objetos en el formato correcto (nativo), hay que serializarlos para enviarlos.

Lo que se envía es:

'{ "nombre": "Pepe", "edad": 22, "cargo": "botones" }'

Al recibir JSON en JavaScript (de una petición AJAX, por ejemplo), debemos convertir el string en un objeto/array real. Como la sintaxis es idéntica a la de un objeto/array en JavaScript, lo único que tenemos que hacer es 'decirle' al motor de JS que lo interprete. Esto se hace mediante eval("my string") ( por motivos de seguridad es mejor utilizar el objeto JSON como veremos más adelante).

Por ejemplo, si tenemos recibido el JSON del ejemplo anterior mediante AJAX, en la variable ajaxData, basta con hacer:

var empleado = eval ('(' + ajaxData + ')') 

Los dos paréntesis que añadimos son necesarios para que JavaScript interprete correctamente las llaves con las que puede comenzar un string JSON. Lo veremos más detalladamente en otro post.

Ahora ya podemos acceder a todos los datos internos de la forma habitual:

alert ( empleado.name );
alert ( empleado.edad);

Debido a los problemas de seguridad que puede provocar el uso de eval(), se ha incluido en los navegadores, de forma nativa, el objeto JSON. Para 'evaluar' un string JSON que hemos recibido sólo tenemos que hacer:

var empleado = JSON.parse(ajaxData);

Y ya tenemos el objeto nativo en la variable empleado.

Si queremos convertir un objeto/array en un string para enviarlo como JSON hacemos:


JSON.stringify( empleado );

Si tenemos que dar soporte algún navegador antiguo que no tenga el objeto JSON ( IE6 e IE7 ) podemos utilizar alguna de las múltiples librerias que hacen lo mismo, como JSON2 o jQuery ( que proporciona el método .parseJSON() ).

Fuentes:
JSON
JSON, wikipedia
JSON: The Fat-Free Alternative to XML
Tutorial JSON

domingo, 30 de septiembre de 2012

Preservando el contexto *this*. $.proxy() y bind()

Como hemos visto en algún post anterior, el valor de this en una función representa el contexto en el que se ejecuta y depende de cómo se la llame. Cuando utilizamos la función como un callback, es muy probable que el valor de this no sea el que esperamos cuando finalmente se ejecuta.
Supongamos que tenemos el siguiente objeto:
var myObject = {
    myName: "Hulk",
    showMyName: function() {  alert(  "My Name Is: " + this.myName );}
}
Es muy importante que, cuando utilicemos showMyName() como callback, this siga haciendo referencia al objeto myObject, para que this.myName sea “Hulk”. Sin embargo, la mayoría de las veces no será así. Al ejecutarse desde otro contexto, el valor de this será diferente. Por ejemplo:

//como callback en setTimeout
setTimeout( myObject.showMyName, 1000); 

//como callback en el click de un botón
$(".button1").click( myObject.showMyName );


En los dos casos perdemos el contexto original y el resultado es:

“My Name Is: undefined”

En el primer caso this será el objeto global window y en el segundo caso será el elemento button del DOM. Ninguno de estos dos objetos tiene una propiedad llamada myName, por lo que this.myName es undefined en ese contexto.

A veces necesitamos asegurarnos de que un callback se va a ejecutar con el contexto que nosotros necesitamos. Es decir, que el valor de this no nos va a dar sorpresas y tendrá el valor que queramos. En cualquier proyecto grande necesitaremos una función que nos asegure esto.

Muchas librerias y frameworks proporcionan una solución propia a este problema, por ejemplo jQuery tiene la función $.proxy(), Prototype tiene una función bind(), Ext JS tiene createDelegate(), Dojo tiene hitch(), etc. La última versión de JavaScript, ECMAscript 5, ha incluido también el método .bind() como solución nativa.

Si tenemos que dar soporte a navegadores que no soportan bind() de ECMAscript 5 y no tenemos necesidad de incluir ninguna de estas librerías o frameworks, podemos crear nosotros mismos nuestra utilidad para esto.

Creando nuestra función proxy

Lo que tenemos que hacer es sencillo, envolver la función original en otra que nos asegure el contexto y que se pueda utilizar como callback en lugar del método original. Es decir, una función intermediaria ( proxy ).

Vamos a crear una función createProxyFunction( context, originalFunc ) con dos argumentos: el contexto que debemos preservar ( this ) y la función original. Devolverá una función que puede usarse exactamente igual que la original, pero asegurando el valor de this. El uso sería tan sencillo como:

var myProxyFunc = createProxyFunction( myObject,  myObject.showMyName ); 
$(".button1").click( myProxyFunc );


o, ahorrandonos la variable intermedia:

$(".button1").click( createProxyFunction( myObject,  myObject.showMyName) );


Podemos hacer esto simplemente utilizando los métodos call() o apply() que tienen todas las funciones en JavaScript. Devolveremos una función que llamará a la original utilizando apply() para asignar el contexto.

Una implementación simple sería:

function createProxyFunction ( context, originalFunc ) {
    var proxyFunction = function() {
        return originalFunc.apply( context, arguments );
};
return proxyFunction;
} 


Podríamos complicarlo un poco para permitir añadir argumentos ‘locales’ que se sumarían a los argumentos con los que se llamará al callback cuando se ejecute:

function createProxyFunction ( context, originalFunc ) {
    //store additional arguments (if any) appart from context and originalFunc 
    var proxyArgs = Array.prototype.slice.call(arguments, 2);
    var proxyFunction = function() {
        var allArgs = proxyArgs.concat ( Array.prototype.slice.call(arguments) );
        return originalFunc.apply( context, allArgs );
};
return proxyFunction;
} 


Utilizamos la función slice() de la ‘clase’ Array porque arguments es un pseudo-array y no la tiene. El valor que devuelve sí es un array real y por eso podemos utilizar concat().

La función que se devuelve en este caso tiene concatenados los argumentos que pasemos a createProxyFunction() (despues de context y originalFunc ) con los que se incluyan en la función original por parte de quien ejecute el callback. Es lo mismo que hace $.proxy() de jQuery.

¿Para qué sirven los argumentos extra?

La opción de añadir parámetros extra es muy útil porque podemos estar manejando información, externa al objeto que enviamos como contexto, que necesitaremos conocer cuando recibamos la llamada a nuestro callback.

Los parámetros que recibimos normalmente en un callback estarán fijados por un API. Por ejemplo, para un evento click, jQuery lanzará nuestro callback con eventObject como único argumento:

eventHandler( eventObject)

Si utilizamos la función $.get() de jQuery para pedir unos datos por AJAX, nuestro callback será invocado cuando los datos estén listos con los argumentos:

myAjaxCallback( data, textStatus, jqXHR )

Puede ocurrir que estemos manejando unos datos concretos y, en función de estos, hagamos una llamada AJAX. La respuesta de la llamada AJAX nos llegará cuando se invoque nuestro callback, pero necesitamos seguir teniendo acceso a los datos que estábamos manejando antes para terminar la tarea. La solución sería añadir estos datos como parámetros extra:

$.get('ajax/test.html', createProxyFunction( myObject, myAjaxCallback, extraParam1, extraParam2 );

Por supuesto la función myAjaxCallback tiene que estar preparada para recibir todos estos parámetros:

myAjaxCallback( extraParam1, extraParam2, data, textStatus, jqXHR ); 


ECMAScript 5 bind()

En la implementación de ECMAScript 5, bind() es un método nativo de las funciones que devuelve una nueva función con el contexto fijado. En nuestro ejemplo lo utilizaríamos así:

$(".button1").click( myObject.showMyName.bind( myObject ) );


También pueden añadirse parámetros extra si los necesitamos:

$(".button1").click( myObject.showMyName.bind( myObject, extraParam1, extraParam2 ) );


Recibiremos los parámetros extra delante:

callbackFunction ( extraParam1, extraParam2, param1, param2 );


En que se diferencia de myObject.showMyName.call( myObject )?

A veces se plantea la pregunta de si podríamos usar directamente:

$(".button1").click( myObject.showMyName.call( myObject ) );


en vez de :

$(".button1").click( myObject.showMyName.bind( myObject ) );


No es lo mismo. La diferencia es que bind() devuelve una función que es la que actúa como callback. Utilizando call() estamos ejecutando directamente el método, no sirve como callback. Las dos expresiones no son equivalentes.


viernes, 28 de septiembre de 2012

Ajustar el ancho de un DIV al contenido

Por defecto el ancho de un div (o de cualquier elemento de bloque) se expande hasta ocupar el 100% del espacio disponible. A veces podemos necesitar cambiar este comportamiento para que se ajuste automáticamente al ancho de su contenido:


Hay varias formas de conseguir esto pero todas son ‘pequeñas chapuzas’ y tienen efectos secundarios. CSS no proporciona una forma elegante de hacerlo.
En el estándar CSS, ajustar el ancho al contenido es sólo un recurso para las situaciones en las que se necesita asignar un ancho y no hay uno definido ni fijado por defecto. Lo que necesitamos es crear una de estas situaciones, que son:
  • float
  • posición absoluta
  • inline-block ( o inline)
  • table

Float

.myDiv {
    float:left;  /* o float:right;*/
}
Haciendo el elemento flotante conseguimos el objetivo, pero es necesario conocer muy bien las propiedades de los elementos flotantes porque los efectos secundarios afectan al comportamiento del div y al resto de contenido.

Posición absoluta

.myDiv {
    position:absolute;
}
Esta solución también tiene efectos secundarios importantes:

  • El div sale del flujo natural de elementos en la página y no ocupa espacio para el resto de elementos, que pueden descolocarse.
  • Se posiciona con respecto al elemento que lo contiene ( si éste está posicionado ).


Inline-block

.myDiv {
    display:inline-block;
}
Esta solución es, quizá, la más elegante. Hay un par de cosas que tenemos que tener en cuenta:
  • El elemento se colocará ‘en línea’ con otros elementos, si los hay.
  • Para que funcione en IE7 necesita un hack o cambiar el div por un span.
El problema con IE7 ( y con IE6 pero ya es hora de ir descartándolo ) es que sólo soportan inline-block para elementos que son inline por defecto. Por eso, a parte del hack, una solución sencilla es cambiar el div por un span y aplicarle display:inline-block. El resultado en el resto de navegadores será el correcto.

Table

.myDiv {
    display:table;
}
Dejando aparte el estigma que tiene la palabra table, este es un método que apenas tiene efectos secundarios. El único problema es que no funciona en IE6/7.

Ajustar al contenido es costoso (poco eficiente)

Siempre que podamos es preferible utilizar anchos fijos o anchos asignados por defecto. Para el navegador es un proceso mucho más sencillo. Para presentar un elemento de bloque que se ajuste automáticamente a su contenido debe primero calcular los tamaños de todos los contenidos y despues volver al elemento contenedor para calcular su anchura y presentarlo.


Fuentes:
CSS “shrink wrap”
StackOverflow Cross browser inline-block

domingo, 23 de septiembre de 2012

JavaScript: El contexto *this* en callbacks

El valor del puntero this en JavaScript es uno de los grandes enigmas con que los que se enfrenta el que empieza a manejar el lenguaje. En principio parece sencillo. Dentro de un objeto, el puntero this hace referencia al propio objeto ¿o no?:
var myObject = {
    message: “Hello!”,
    talk: function() {
        alert(“I say: ” + this.message);
    }
}
cuando hacemos referencia a this.message estamos apuntando a la propiedad message en el contexto del objeto myObject. Por lo tanto this es una referencia al objeto en el que estamos.
Si hacemos:

myObject.talk();

veremos el mensaje:

"I say: Hello"

Parece fácil, pero se complica y mucho.

El contexto de un callback

Supongamos que queremos utilizar el método myObject.talk() como callback o event handler que se ejecuta al pulsar un botón:
$(".button1").click( myObject.talk );
Al hacer click en el botón veremos:

"I say: undefined"

¡¿Undefined?!. Cuando se llama al método myObject.talk al hacer click en el botón, el valor de this.message es undefined. La razón es que this ya no apunta al objeto myObject, hace referencia a otro contexto diferente.

En este caso, al ser un callback de un evento del DOM, el navegador asocia this al elemento que provoca el evento ( si usamos addEventListener,  que es la opción que utiliza jQuery si el navegador lo permite ). Es decir, this es el objeto button. Como dentro de este objeto no hay ninguna propiedad que se llame message, this.message es undefined.

No es el único caso en que se cambia el contexto. Si lo usamos como callback de una llamada AJAX o de setTimeout() tampoco tendrá el valor original.

Y por si las cosas no fueran ya bastante complicadas, resulta que si ponemos el método dentro de una función anónima, el mensaje es correcto:

$(".button1").click(function() {
    myObject.talk();
});


El resultado es:

"I say: Hello!"

Es casi igual que lo que teníamos antes, llamámos al método myObject.talk() pero ahora dentro de una función ¿por qué ahora sí funciona?. Bueno, el valor de this ahora sí es el objeto myObject. Lo explicaremos un poco más adelante.

Vamos a ver como se comporta el puntero this en funciones/métodos y después volveremos sobre este ejemplo para explicar qué es lo que está pasando.

this en funciones y métodos

Cuando tenemos una referencia a this dentro de una función, su valor dependerá siempre de cómo se llama a la función. 

Por ejemplo, si hacemos:
var f1 = myObject.talk;
f1();  //this.message is undefined
Estamos llamando a la función talk() de una forma diferente, desde fuera del objeto. En este caso this será el contexto desde el que ejecutamos f1(), que es el objeto global (window).

 Sin embargo, si ejecutamos la función como un método de un objeto concreto, el valor de this será ese objeto:

myObject.talk(); //this.message is "Hello!"

Podríamos incluso llamar a la misma función desde otro objeto diferente:

var Object2 = {
  message: "I'm OBJECT2",
}

Object2.talk = myObject.talk;

Object2.talk(); //this.message is "I'm OBJECT2"

En el alert en pantalla veremos:

"I say: I'm OBJECT2"

Volviendo al ejemplo del callback

Ahora podemos entender qué estaba pasando en nuestros dos ejemplos iniciales. Recordemos que teníamos la función talk() como callback de dos formas diferentes:
//Example 1
$(".button1").click( myObject.talk );

//Example 2
$(".button1").click(function() {
    myObject.talk();
});


En el primer caso le estamos pasando una referencia directa a nuestra función, para que la ejecute cuando y como quiera. Como hemos visto antes, el valor de this dependerá de cómo se llame a la función. Nosotros ya no tenemos el control sobre cómo se la llamará, por eso el valor del contexto ya no es nuestro objeto.

El navegador, cuando llame al callback, colocará el contexto del objeto del DOM que ha lanzado el evento.

En el segundo caso se llama a la función anónima también con el contexto del elemento button, pero dentro de esta función estamos ejecutando explícitamente un método del objeto myObject:


myObject.talk();

Es una llamada directa al método dentro del objeto concreto y, como hemos visto antes, el contexto será el del objeto que se referencia al llamarlo. Por eso aquí el puntero this es correcto.

Hay varias formas de asegurarnos de que el contexto con el que se llama a una función es el que nosotros queremos, como Function.apply(), Function.call() o utilizando una función proxy, pero esto lo veremos en otro post.

 Fuentes:
  MDN This


viernes, 21 de septiembre de 2012

¿Que es el HTML5 Shiv?

HTML5 Shiv (o Shim) es un hack necesario para poder utilizar los nuevos elementos semánticos de HTML5 (header, footer, article, etc ) en IE8 y anteriores. Vamos a ver en detalle cual es el problema y cómo se soluciona.

Internet Explorer ignora las nuevas etiquetas

El problema es que al utilizar las nuevas etiquetas para estructurar una página web, la presentación final va a depender totalmente de los estilos que apliquemos a esas etiquetas. El Internet Explorer ( versión 8 y anteriores ) no aplica los estilos a las etiquetas nuevas porque no las reconoce. Ignora las etiquetas y los estilos asociados.

Si hemos creado un documento utilizando, por ejemplo:

My Great Web Header

y los correspondientes estilos en CSS:

header {
    border: 1px solid black;
    background-color: wheat;
    font-size: 160%;
    padding: 10px;
}

Lo que esperamos ver es algo así:

Lo que verán los visitantes que utilicen el IE8 o inferior es:

Esto evidentemente nos obliga a buscar alguna solución si tenemos que dar soporte a estos navegadores y queremos utilizar las etiquetas nuevas. Esta solución es lo que se ha llamado HTML5 Shiv.

La solución para que IE aplique CSS

Afortunadamente alguien descubrió un hack muy sencillo que permite aplicar reglas CSS a elementos que el IE no reconoce. Sólo tenemos que crear explícitamente el elemento con document.createElement( elemento ).

Es decir, que bastaría con crear los elementos que vayamos a usar en la cabecera de nuestro documento:

<!DOCTYPE html>
<html lang="es">
  <head>
     
     Ejemplo de HTML5 Shiv
     
  </head>
  ...

Como es un código de uso habitual y que sólamente necesitamos ejecutar cuando la página se cargue en un IE6, IE7 o IE8, lo mejor es separarlo en un fichero externo y cargarlo de forma condicional para IE<9 :





Es necesario colocarlo en la cabecera porque el Internet Explorer necesita reconocer los elementos para poder presentarlos.

Hay que tener en cuenta también que, por defecto, estos elementos nuevos para el IE van a ser elementos de línea. Si queremos que sean elementos de bloque ( en la mayoría de los casos es lo normal ) tenemos que darles este estilo explícitamente en nuestro CSS:


header,nav,article,footer,
section,aside,figure,figcaption{display:block}

Utiliza el script ‘oficial’

El script html5shiv.js mantenido en GitHub por Alexander Farkas se ha convertido en el estándar de facto para utilizar los elementos de HTML5 en Internet Explorer anteriores al IE9.

Es recomendable utilizarlo porque soluciona otros problemas relacionados que se han ido encontrando con el tiempo ( problemas al imprimir y al manejar dinámicamente las etiquetas con innerHTML ).

Si sólamente necesitas dar estilo a los elementos, el código que hemos descrito antes puede servirte, pero utilizando el script html5shiv.js sabes que tienes cubiertos todos los problemas relacionados que se han encontrado hasta ahora y que ha sido probado por muchos miles de personas. Estas son las ventajas del software libre y de la colaboración.

Nota: Este script viene también incluido en la popular librería Modernizr, no es necesario incluirlo a parte.

Fuentes:
HTML5 Shiv
The Story of the HTML5 Shiv