Mostrando entradas con la etiqueta css. Mostrar todas las entradas
Mostrando entradas con la etiqueta css. Mostrar todas las entradas

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.

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

viernes, 12 de julio de 2013

¿Puede un ID de HTML ser un número?

¿Es correcto asignar un número como ID de un elemento en HTML?¿nos puede dar problemas?

<div id="1"> - </div>

La respuesta rápida: es correcto en HTML5 e incorrecto en las versiones anteriores. Y para la segunda pregunta, la respuesta es sí, nos puede dar problemas al tratar de asignarle estilos con CSS. Mejor no utilizarlo.

Diferencias entre HTML4.01 y HTML5

Según la especificación HTML4.01, un ID sólo puede empezar con una letra:

ID must begin with a letter ([A-Za-z]) and may be followed by any number of letters, digits ([0-9]), hyphens ("-"), underscores ("_"), colons (":"), and periods (".").

Las clases, sin embargo, no tienen esta restricción, no tienen que empezar por una letra para ser válidas.

HTML5 elimina también esta restricción para las IDs:

The value must be unique [...] and must contain at least one character. The value must not contain any space characters.

Las única limitaciones que impone para una ID es que no quede vacía y que no contenga espacios.

Válido para HTML pero no para CSS

El problema viene a la hora de intentar asignar estilos. En CSS los identificadores NO pueden empezar con un número. La siguiente definición no es válida y los estilos no se aplicarán:

#1 {
    border: 1px solid red;
}

El '1' no es un identificador válido para CSS ( CSS2.1 identifiers es la especificación referenciada por CSS3 a la hora de definir los ID válidos ):

In CSS, identifiers (including element names, classes, and IDs in selectors) can contain only the characters [a-zA-Z0-9] and ISO 10646 characters U+00A0 and higher, plus the hyphen (-) and the underscore (_); they cannot start with a digit, two hyphens, or a hyphen followed by a digit. Identifiers can also contain escaped characters and any ISO 10646 character as a numeric code (see next item). For instance, the identifier "B&W?" may be written as "B\&W\?" or "B\26 W\3F".

Con las clases tenemos el mismo problema, tampoco sería válido como identificador de clase. Ninguno de los siguientes estilos se aplicaría:

.1 {
    border: 1px solid red;
}

#33wrapper {
    background-color: blue;

}

.2box {
    margin: 0 auto;
}

Por lo tanto, pueden usarse si sólo utilizamos la ID para seleccionar el elemento con JavaScript, pero es mejor no utilizarlo si vamos a dar estilos CSS basandonos en esa ID.

Fuentes:
What are valid values for the id attribute in HTML?
CSS character escape sequences

jueves, 30 de mayo de 2013

Simular "text-overflow:ellipsis" para textos largos ( multilínea )

En CSS, si utilizamos las siguientes propiedades:
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
Podemos conseguir que un texto se corte a la anchura que queramos y se inserten automáticamente unos puntos suspensivos al final.



El problema es que sólo funciona para una única línea. El texto se corta cuando la línea sobrepasa la anchura del contenedor. Necesitamos incluir white-space: nowrap para evitar que el texto que no cabe se desplace a la línea siguiente.
Sería muy util poder hacer también algo como esto:



Es decir, tenemos un texto largo, de varias líneas ( sin white-space: nowrap ), y queremos que se corte mostrando "..." cuando supera la altura del contenedor.

Ellipsis multilínea con JavaScript

Sólo son necesarias unas líneas de JavaScript para conseguirlo. Supongamos que tenemos un texto largo en un div contenedor con una altura limitada:
<div id="container">
  <p>
  Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  </p>
</div>

Tenemos el siguiente CSS para limitar la altura y anchura del contenedor y ocultar el texto que no cabe:
#container {
  width: 300px;
  height: 95px;
  overflow: hidden;
}
El texto quedaría cortado pero no tenemos ninguna indicación de ello:



Podemos solucionar el problema con unas lineas de JavaScript (y JQuery):
var containerHeight = $("#container").height();
var $text = $("#container p");

while ( $text.outerHeight() > containerHeight ) {
        $text.text(function (index, text) {
            return text.replace(/\W*\s(\S)*$/, '...');
       });
}
El resultado es:



Lo que hace este pequeño script es ir recortando palabras del final del texto hasta que la altura del texto es igual a la altura del contenedor.Toda la magia se realiza con la expresión regular:
text.replace(/\W*\s(\S)*$/, '...');
Básicamente esta instrucción sustituye la última palabra, junto con cualquier espacio en blanco que tenga delante, por "...". Esto se va repitiendo hasta que el texto encaja dentro del contenedor.

Creando una función genérica

Podemos hacerlo más flexible creando una función que incluya los "..." en cualquier texto largo que sobrepase el contenedor. Pasaremos como parámetro el id del div que contiene el texto.
La siguiente función es válida siempre que el marcado HTML sea como en el ejemplo anterior,el texto debe estar englobado en un <p></p> que está dentro del elemento que se pasa como parámetro. No es dificil cambiar la función para otra estructura.
function createEllipsis ( containerId ) {
    $container = $("#" + containerId);
    var containerHeight = $container.height();
    var $text = $container.find("p");

    while ( $text.outerHeight() > containerHeight ) {
        $text.text(function (index, text) {
            return text.replace(/\W*\s(\S)*$/, '...');
        });
    }
  }

Se utilizaría:
createEllipsis("container");

Hay tambien una solución para hacer algo parecido con CSS descrita en el post Multiline ellipsis in pure css pero tiene varios problemas. Necesita algún marcado extra en el HTML y, la más grave, si la línea en la que cortamos es corta (un punto y aparte), los puntos suspensivos quedan siempre pegados a la derecha y queda un hueco en blanco.

miércoles, 6 de marzo de 2013

Tutorial: como hacer tooltips con CSS

Un tooltip es esa ventanita de información que aparece cuando colocamos el ratón sobre algún elemento, como podemos ver en esta imagen de un botón de Gmail:


Se puede implementar de muchas maneras, aquí vamos a ver las 2 opciones más sencillas: con HTML y con CSS. Dejaremos para otra entrada la implementación con JavaScript.

HTML, tooltips básicos con el atributo title


En HTML el atributo title puede utilizarse para mostrar un tooltip básico. Es válido para casi todos los elementos ( en HTML5 ya se puede incluir en todos ):
<button title="This is a tooltip" type="button">Press</button>
El problema es que no admite ningún tipo de personalización. Sólo puede mostrarse texto simple, no podemos formatearlo mediante etiquetas HTML ni poner saltos de línea donde queramos.

Elementos de un tooltip

Los conceptos para crear un tooltip propio son sencillos, básicamente el mensaje no es más que un elemento HTML, normalmente un span o un div, con un texto informativo dentro.

<div class="tooltip">
This is a tooltip
</div>
Despues, mediante estilos CSS, le damos el aspecto que queramos y lo posicionamos donde corresponda con posicionamiento absoluto para que no desplace a otros elementos de la página al mostrarse:

.tooltip {
  position: absolute;
  padding: 10px;
  background-color: gray;
  color: white;
  top: 100%;
  left: 95%;
}

Jugando con los estilos podemos crear ejemplos espectaculares como estos, sacados del post [CSS3 tooltips de Catalin Rosu] (http://www.red-team-design.com/css3-tooltips):


Tooltips usando sólo CSS. El método tradicional

Para crear el mensaje utilizando sólo CSS vamos a incluir el texto de información en un span que inicialmente estará oculto ( display: none). Para que se muestre cuando colocamos el ratón encima (hover) definiremos un estilo diferente para la pseudo-clase :hover con display: block.
<button>Press
    <span class="tooltip">This is a tooltip</span>
</button>
El siguiente paso es definir el CSS para darle el aspecto que queramos, colocarlo en el lugar donde debe mostrarse y definirlo como oculto por defecto y visible sólo en el :hover .
button {
  position: relative;
}

.tooltip {
  position: absolute;
  display: none;
  border: 1px solid black;
  padding: 3px;
  background-color: gray;
  color: white;
  width: 100px;
  left: 100%;
  top: 100%;
}

button:hover .tooltip {
    display:block;
}

Nos quedaría:



Para que el mensaje aparezca siempre en la esquina inferior izquierda del elemento, hemos definido la posición como:

position: absolute;
top: 100%;
left: 100%;

El problema de este método es que el HTML queda confuso y poco semántico porque el span del mensaje se incluye dentro del elemento. Si queremos ponerlo fuera tenemos que "envolverlos" en un div o span extra de forma que sea este elemento el que muestra el tooltip al hacer hover con el ratón y nos sirva como marco para que aparezca posicionado con respecto al elemento.

//HTML
<div class="tooltipWrapper">
<button>Press</button>
<span class="tooltip">This is a tooltip</span>
</div>
//CSS

.tooltipWrapper {
  display: inline-block;
  position: relative;
}

.tooltip {
  position: absolute;
  display: none;
  border: 1px solid black;
  padding: 5px;
  background-color: gray;
  color: white;
  width: 100px;
  left: 50%;
  top: 100%;
}

.tooltipWrapper:hover .tooltip {
    display:block;
}

El display: inline-block se pone para que el div se ajuste al tamaño del contenido. Si no lo ponemos tendría todo el ancho del navegador. En la siguiente imagen se puede ver cómo quedaría. El div.tooltipWrapper está marcado con un borde rojo para verlo:



En esta ocasión hemos puesto left: 50% para que aparezca más centrado.
Si queremos mostrar el mensaje sobre una imagen necesitamos este div envolvente ( wrapper ) porque la etiqueta <img> no encierra contenido:

<div class="tooltipWrapper">
<img src="myImage.jpg" />
    <span class=".tooltip">This is a tooltip</span>
</div>
Con el mismo CSS del ejemplo anterior obtenemos:



Jugando con los estilos podemos darle el aspecto que queramos, incluso incluir transiciones o animaciones para para que se muestre más lentamente o vaya variando la opacidad ( en los navegadores que lo soporten ). En el siguiente ejemplo utilizamos el pseudo elemento :before para crear el pequeño triángulo que apunta al elemento y hacerlo similar al de Google que mostramos en la primera imagen:
//HTML
This is a tooltip
//CSS .tooltipWrapper { display: inline-block; position: relative; } .tooltip { position: absolute; display: none; border: 1px solid black; padding: 5px; background-color: gray; color: white; width: 100px; left: -50%; bottom: -37px; } .tooltip:before{ content: ' '; display: block; position: absolute; left: 45px; top: -8px; width: 14px; height: 14px; border-color: black; border-width: 1px; border-style: solid none none solid; background-color: gray; transform: rotate(45deg); -webkit-transform: rotate(45deg); -ms-transform: rotate(45deg); -moz-transform: rotate(45deg); } .tooltipWrapper:hover .tooltip { display:block; }
El resultado es:


Limitaciones del método tradicional

Como hemos visto no es muy semántico porque tenemos un elemento extraño dentro del contenido del botón (el span) o un elemento extra que envuelva el elemento y el tooltip. Podemos solucionarlo utilizando CSS3 para coger el valor de un atributo HTML y colocarlo como contenido de un elemento.

Tooltips con CSS3 utilizando un atributo de HTML para el contenido

Este método es mucho más semántico porque no necesitamos el span para el contenido del tooltip ni el div extra que lo envuelve. Utilizamos un atributo personalizado de HTML del tipo data- para el mensaje y el pseudo-elemento ::before para construir el tooltip:
//HTML
<button class="tooltip2" data-tooltip="this is the tooltip!">
    Press
</button>    

//CSS
.tooltip2 {
  position: relative;
}

.tooltip2::before {
    position:absolute;
    display: none;
    content: attr(data-tooltip) ;
    border: 1px solid black;
    padding: 3px;
    background-color:gray;
    color: white;
    white-space:nowrap;
    left: 50%;
    top: 100%;
 }

.tooltip2:hover::before {
    display: block;

 }




El texto del tooltip se coge del atributo data-tooltip mediante la línea CSS3:
content: attr(data-tooltip) ;
Podriamos utilizar title como vimos al principio, pero aparecería nuestro mensaje y el del navegador al mismo tiempo.
Recordemos que tenemos aún un pseudo-elemento extra disponible ( ::after ) por si queremos añadir también el pequeño triángulo que apunta al elemento.

El inconveniente de tener el texto en el atributo es que deben ser textos sencillos. No podemos crear textos complicados  con formato o imágenes.

Fuentes:
W3 Org title definiton
Simple cross-browser tooltip with CSS
Tooltips courtesy of HTML5 data attributes

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.