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