Ir directamente al contenido de esta página
Creo que todos, sin excepción, al empezar a trabajar con CSS hemos tenido que revisar páginas y páginas para aprender a crear diseños a varias columnas. La verdad es que es todo un arte, y no hay curso o manual de CSS que se precie que no tenga una sección dedicada a ese tema —por cierto, ésta es la mía—. Y entonces viene una secuencia de pasos como esta:
Contentísimos, nos ponemos a aplicarlo, y parece que funciona, como en este ejemplo…
…siempre y cuando empleemos Internet Explorer. Para Firefox, u Opera o Safari, el resultados es éste:
Como se ve, la imagen que hemos empleado para crear las falsas columnas no se muestra. ¿Por qué? Bueno, en realidad se debe a que al principio todos tenemos la tendencia a crear un marcado como éste:
<div id="contenedor">
<div id="contenido">
…
</div>
<div id="contenido_secundario">
…
</div>
</div>
En realidad, si nos fijamos, esa capa llamada contenedor
no es muy semántica. Pero lo importante es que no tiene más contenido que los dos elementos que se flotan. Y la especificación dice:
Since a float is not in the flow, non-positioned block boxes created before and after the float box flow vertically as if the float didn't exist.
[En al medida en que un flotado no pertenece al flujo, las cajas de bloque no posicionadas creadas antes y después de la caja flotada fluyen verticalmente como si el flotado no existiese.]
En idioma común, supone que la caja que contiene al elemento flotado sólo debe extenderse hasta lo necesario para albergar el contenido no flotado. Como contenedor
no tiene ninguno, se contrae hasta desaparecer. Sí, lo de Internet Explorer es un error en el soporte de la especificación.
Como tantas otras veces, solucionar un problema nos lleva a descubrir otros.
div
Llegados a este punto, sabemos que el problema es que necesitamos algún contenido en contenedor
tras las columnas que podamos limpiar por medio de clear
, y así forzar al elemento padre a extenderse hasta cubrir nuestras columnas.
Y antes o después algún oscuro mecanismo se dispara en la cabeza de todo iniciado al CSS que se enfrenta a esta situación, y que le hace codificar esto:
<div id="contenedor">
<div id="contenido">
…
</div>
<div id="contenido_secundario">
…
</div>
<div style="clear:both"></div>
</div>
Reconocedlo.
Y si no lo hacéis, bueno, creo que los datos de Google me respaldan: <div style="clear:both"></div>
tal día como hoy ofrece 817.000 resultados, mientras que su versión <div><span style="clear:both"> </span></div>
—más absurda, sin duda alguna …1— suma 583.000.
El caso es que funciona. En este punto, si emplear un elemento estructural de manera no semántica no supone un problema para el lector, puede dejar de leer.
Bien, si sigue leyendo al menos tiene curiosidad.
Personalmente, para evitar este problema, si puedo asignar la imagen de las falsas columnas al body
, lo hago, con lo que además me ahorro la capa contenedor
. Pero esta solución sólo se puede aplicar en dos supuestos:
En los demás casos —mal que me pese— necesito la capa contenedor
, porque si no ocurre algo como esto:
Pero eso no significa que tenga que resignarme y aceptar además otro div
vacío para limpiar los flotados, así que…
Así que, recuerdo un elemento bastante devaluado —aunque aún válido— que es hr
2, que crea una regla horizontal cuya finalidad es precisamente dividir visualmente un contenido indicando diferentes secciones estructurales. En este caso, lo empleo para separar el contenido del documento de su pie, lo que no creo que sea forzar su semántica. En última instancia, al menos, no la fuerza tanto como un div
vacío.
En este ejemplo se puede comprobar su funcionamiento.
Para finalizar, una nota sobre cómo hacerlo invisible:
border:0
.width:0
. No, no vale simplemente con height:0
, sigue creando una línea de 1 pixel.Bien, sigue sin ser la solución ideal, pero tampoco vivimos en un mundo perfecto…
Otra solución alternativa es la de emplear el pseudoelemento :after
para añadir un contenido tras el elemento a limpiar. Si bien desde el punto de vista del marcado es más semántico, resulta una solución muy poco elegante, por los problemas adicionales que plantea. Y si no, ver How To Clear Floats Without Structural Markup en positioniseverything.net (inglés). Así que, por supuesto, defiendo mi método para la situación que he descrito.
…puesto que luego de alguna forma hay que asignar display:block
a ese span
para que funcione. Así que ya puestos, propongo la versión a-semántica definitiva:
<div style="height:0;overflow:hidden;">
<p><span><strong><span><i>
<span style="clear:both;"> </span>
</i></span></strong></span></p>
</div>
Ésta además tiene la virtud de no generar advertencias en el Tidy.
hr
está condenado a desaparecer. En XHTML 1.1 está relegado al módulo de presentación (inglés), y en el actual boceto de XHTML 2.0 desaparece en favor de separator
(inglés). Pero de momento no tenemos nada mejor.