19 junio, 2008

CSS: Posicionamiento absoluto Faux

Traducido del artículo de Eric Sol en A List Apart. Lo he leído y me ha parecido más que interesante por lo que lo he traducido entero.

Hay dos enfoques populares para el posicionamiento con CSS: float y posicionamiento absoluto (position:absolute). Ambos métodos tienen sus pros y sus contras. Mi equipo y yo hemos desarrollado un nuevo enfoque de posicionamiento que nos da lo mejor de ambos mundos. Después de un poco de experimentación y ensayo, es el momento de compartir la técnica con el resto del mundo y ver cómo podemos trabajar juntos para mejorarla. Yo la llamo "posición absoluta faux" debido a la técnica de columnas falsas (faux) que simula la presencia de una columna.

¿Por qué necesitamos otra técnica de diseño CSS?



Muchos diseños de sitio web se basan en una disposición de columnas con una cabecera y pie de página. Con diseños totalmente posicionado, es casi imposible colocar el pie de página si las columnas pueden crecer verticalmente. Con diseños float, cambios inesperados de contenido pueden causar que columnas enteras salten de su envoltura ( "float drop"), tal y como se describe por Shaun Inman en Clearance. Esto es indeseable y difícil de controlar con Internet Explorer debido al tratamiento problemático por IE de width.

Nuestro caso de uso es aún más complejo: mi equipo estaba desarrollando un generador de formularios WYSIWYG basado en web que permite al usuario arrastrar elementos a lugares arbitrarios dentro del lienzo (canvas). Teníamos que dejar que nuestros usuarios creasen atractivos formularios que no usasen posicionamiento estático y que les dejase alinear columnas cuando sea necesario.

Por ejemplo, supongamos que queremos un formulario que tenga los campos de código postal y ciudad en la misma fila porque están relacionados semánticamente. Para lograr esto, hemos intentado utilizar posicionamiento flotante inspirado por la técnica del Santo Grial. El uso de este método necesita que ajustemos el ancho, los bordes, los márgenes, y/o el relleno interior (padding) del campo código postal para ajustar el campo ciudad a una determinada posición horizontal. Pero esto era un problema porque si la anchura del campo del código postal necesitaba un ajuste, o si queríamos ajustar la cantidad de espacio en blanco entre los campos, el campo de ciudad tendría que ajustarse también. Cuanto más elementos en una página -más celdas en la malla- más tedioso se convierte este tipo de ajuste. Además, el posicionamiento es sensible al más mínimo cambio en una serie de parámetros, por lo que resulta casi imposible de controlar en caso de elementos de formulario dinámicos.

A continuación, intentamos utilizar el posicionamiento absoluto. Esto nos dio mucho más control sobre el posicionamiento de estos elementos y es robusto. Pero los elementos posicionados absolutamente no tienen altura, y eso causó que el elemento contenedor (el canvas) se comprimiese verticalmente. Esto hacía difícil posicionar contenido sin hacerlo todo posicionado absolutamente - lo cual es imposible de lograr con contenido dinámico.

Un enfoque diferente



Por último, intentamos una solución basada en encontrar la manera de calcular la compensación (offset) a la izquierda desde una posición fija, en contraposición a calcularla desde el borde derecho del elemento anterior. Lo hemos conseguido utilizando una combinación de position: relative, left: 100% y un margin-left negativo.

Nuestro método comienza por la construcción de una malla de líneas y elementos. Podemos colocar cualquier número de elementos en una línea y cualquier número de líneas en el elemento contenedor:

<div id="canvas">
  <div class="line">
    <div class="item" id="item1">
      <div class="sap-content">contenido aquí</div>
    </div>
  </div>
</div>

... y así sucesivamente. Cada elemento tiene un div sap-content extra con varios propósitos:

  • Evita el redraw bug en IE6,
  • nos da más flexibilidad para añadir relleno interior (ver ejemplo a continuación), y
  • nos permite jugar con position:overflow (sin romper la malla).


El CSS genérico aplicado a estos elementos es el siguiente:

.line {
  float: left;
  width: 100%;
  display: block;
  position: relative;
}

.item {
  position: relative;
  float: left;
  left: 100%;
}

Para colocar un elemento en particular, todo lo que hay que hacer es darle un margin-left negativo y una anchura. Por ejemplo:

#item1 {
  margin-left: -100%;
  width: 30%;
}

Con algo más de estilo, a efectos de demostración, sería algo así:

Ejemplo de Posicionamiento absoluto Faux en acción.

El CSS genérico posiciona cada elemento en el lado derecho del canvas, con el ancho de cada elemento basado en su contenido y todos los elementos flotados en el orden del código fuente HTML. El margin-left es ahora un desplazamiento de compensación (offset) desde la parte derecha del canvas en lugar de serlo desde el elemento a su izquierda.

Ventajas



Con el posicionamiento absoluto faux, podemos alinear todos los elementos a una posición predefinida en la malla (al igual que con el posicionamiento absoluto), pero los elementos todavía afectan al flujo normal (y gracias a clear) tiene muchas de las mismas ventajas que con el flujo normal de los elementos. Cada fila de la malla siempre tendrá una altura que depende del contenido o bien tal y como se defina en el CSS, y siempre tomará hasta el 100% de la anchura, sin importar cuántas columnas se definen en la fila. Por otra parte, podemos evitar el uso de engorrosos márgenes o rellenos interiores para ajustar la cantidad de espacio en blanco entre los elementos -lo que es un plus, ya que estas técnicas casi siempre nos obligan a usar hacks específicos para IE6 para compensar el modelo de cajas del navegador.

Otra ventaja de esta técnica es que mitiga gran parte de la fragilidad de los floats. Cuando el contenido de una caja flotada es más amplio que la propia caja, empuja a la siguiente caja hacia la derecha (y como consecuencia, la caja a menudo cae a la siguiente fila rompiendo el diseño). Con el posicionamiento absoluto faux, la caja de la derecha se mantiene en su lugar, no importan las condiciones. El contenido de las cajas puede solaparse (en función de otras variables tales como overflow:hidden), pero eso es todo -y en nuestra opinión, es mejor correr el riesgo de solapamiento que arriesgarse a romper todo el esquema.

Inconvenientes



El posicionamiento absoluto faux está muy inspirado por y destinado a los diseños basados en mallas y es más gratificante con diseños más complejos. Si tienes un diseño de de dos columnas de ancho fijo, esta puede no ser la técnica más apropiada.

Además, el posicionamiento absoluto faux no funciona para todas las situaciones. Si quieres alinear elementos a la izquierda, no puedes utilizar una unidad que sea diferente de la unidad utilizada para la anchura del canvas, porque no se puede calcular el desplazamiento (offset). Por ejemplo, si tienes un ancho de canvas con width:800px y quieres un desplazamiento a la izquierda de 2em para un elemento, no es posible calcular el margen izquierdo porque no se puede saber cuántos ems caben en 800 píxeles.

Y puesto que se trata de una nueva técnica que no ha sido probada por miles de usuarios, debe todavía ser considerada experimental, ya que se pueden ver resultados inesperados con la actual combinación de código HTML, CSS, y navegador.

Una cuestión pendiente: cuando un elemento más ancho que el canvas precede a otros elementos en el código fuente HTML, los elementos posteriores en la misma línea serán empujados a la derecha por una cantidad igual a la diferencia de anchura entre el primer elemento y el canvas.

Ejemplos



El primer ejemplo es un diseño líquido de tres columnas siendo las dos laterales fijas, al igual que el Santo Grial. He implementado esta disposición como una plantilla de Drupal, un popular CMS de código abierto. Pero hay algunas cosas que observar:

  1. Las columnas izquierda y derecha tienen anchos en píxeles. Por lo tanto, no se puede calcular el margen izquierdo para el contenido principal, porque no sabemos el ancho del canvas o el ancho de la columna de la izquierda como un porcentaje del canvas. La solución es similar al Santo Grial: posicionar el contenido principal con margin-left: -100% y width: 100% y añadir el relleno interior (padding) con píxeles para garantizar el espacio necesario para las columnas.
  2. Las columnas izquierda, principal, y derecha se muestran en el mismo nivel jerárquico, por lo que es posible necesitar algo como z-index: 100 en las columnas.
  3. El relleno interior para las columnas izquierda y derecha se añade al div.sap-content extra, lo que mantiene los cálculos simples, a la vez que ofrece una gran cantidad de flexibilidad.
El segundo ejemplo es un diseño líquido de cinco columnas en el que el lienzo, las líneas, y todos los elementos tienen el tamaño definido con porcentajes. La adición de imágenes, bordes y rellenos internos no tienen ningún efecto en el posicionamiento global, incluso en el caso de imágenes que son más grandes que el elemento que las contiene, como se demuestra con el viejo mapa de Maastricht en el ejemplo.

¡No requiere hacks!



Nuestra solución no requiere hacks y funciona con todos los navegadores modernos (Safari, Opera, Firefox, IE7), así como IE6 e incluso IE5.5/Win. No funciona en IE5/Mac, pero ya que este producto ha sido retirado, no está en nuestra lista de prioridades.

La solución también es muy estable, ya que los elementos crecen verticalmente en caso necesario, y la disposición no se rompe cuando una imagen es más ancha que el elemento, por ejemplo. El posicionamiento de los elementos es independiente del orden en el código HTML.

Estoy muy entusiasmado con este planteamiento y le veo muchas posibilidades. Siéntete libre para probar, experimentar y publicar tus comentarios.

2 comentarios:

felipe dijo...

gracias.. me a servido de mucho tu articulo

felipe dijo...

gracias.. me a servido de mucho tu articulo

Publicar un comentario en la entrada

Últimos links en indiza.com