Como remover espacio extra entre img, il y otros elementos inline

Este es el caso: creas un div que funcionará como contenedor horizontal, y dentro colocas algunas imágenes (etiquetas img) de cierto tamaño que deberían aparecer una junto a la otra; y como por arte de magia hay un espacio misterioso entre las imágenes. Intentas corregir el CSS, eliminando márgenes, padding, bordes, pero nada funciona… así…

Espacio entre elementos inline

Espacio entre elementos inline

Este es el caso: creas un div que funcionará como contenedor horizontal, y dentro colocas algunas imágenes (etiquetas img) de cierto tamaño que deberían aparecer una junto a la otra; y como por arte de magia hay un espacio misterioso entre las imágenes. Intentas corregir el CSS, eliminando márgenes, padding, bordes, pero nada funciona… así que buscas en Google y llegas a un artículo como este donde te explican que sucede y te dan una solución 🙂

¿De dónde sale ese espacio de más?

Veamos un ejemplo. Primero el HTML; el div que usé como contenedor tiene un fondo gris para que veamos el espacio adicional, y contiene dos elementos img con imágenes de 100x40px (generadas desde dummyimage.com). Estas dos imágenes deberían aparecer una junto a la otra, y la altura del div debería ser igual a la altura de las imágenes (40px):

<div style="background-color:#777;">
    <img src="http://dummyimage.com/100x40/000/fff&text=A" />
    <img src="http://dummyimage.com/100x40/44f/000&text=B" />;
</div>

Veamos ahora como aparece en pantalla (en casi cualquier navegador se verá igual):

Espacio entre dos elementos img

Podemos notar dos espacios de más; el primero entre los dos elementos img y el segundo debajo de ellos (la zona gris a la derecha es la parte del div que «sobra»). Este espacio aparece cuando tenemos elementos con display:inline o display:inline-block y es causado por los espacios en blanco que escribimos en el HTML (espacio U+0020, tab U+0009, avance línea U+000A y retorno de carro U+000D): en resumen (más o menos) todos los espacios en blanco consecutivos del HTML se interpretan como un solo espacio y éstos afectan la posición de elementos inline o inline-block. Si quieres puedes revisar en la documentación oficial como los navegadores deben procesar ese espacio.

El espacio de más nos trae dos problemas concretos: Primero, hay un espacio «visible» en donde no debería haberlo; segundo, si las imágenes y el div tienen anchos exactos definidos (e.g. 100px para las imágenes y 200px para el div) entonces la última de las imágenes (sean dos imágenes como el ejemplo, o más) aparecerá debajo del resto porque los espacios de más requieren espacio adicional y ya no caben en ancho del contenedor.

Cinco Soluciones

Preparé un jsFiddle con todo el código de este ejemplo, por si quieres verlo funcionar «en vivo» (si estás viendo desde un teléfono o tableta tal vez quieras probar este otro jsFiddle primero); las cinco soluciones las verifiqué en:

  • Ubuntu 14:04: Chrome 33, Firefox 30.
  • Windows 7: Chrome 35, Firefox 30, IE11.
  • Android 4.0.4: Chrome 35, Firefox 30, Navegador Android.

NOTA: en Android 4.0.4 las cinco soluciones funcionan en Chrome y Firefox tal y como se describe, pero en el navegador nativo del SO las soluciones 2 y 5 no tuvieron ningún efecto.

A continuación el código y la explicación. Primero el HTML:

<!-- El problema: los "espacios en blanco" antes y después de los img generan un espacio entre las imágenes en pantalla. -->
<div id="contenedor0">
    <img src="http://dummyimage.com/100x40/000/fff&text=A" />
    <img src="http://dummyimage.com/100x40/44f/000&text=B" />
</div>

<!-- Sol 1: eliminar los espacios del html -->
<div id="contenedor1"><img src="http://dummyimage.com/100x40/f44/fff&text=1A" /><img src="http://dummyimage.com/100x40/ff4/000&text=1B" /></div>

<!-- Sol 2: establecer el tamaño de fuente a 0px -->
<div id="contenedor2">
    <img src="http://dummyimage.com/100x40/622/fff&text=2A" />
    <img src="http://dummyimage.com/100x40/f04/000&text=2B" />
</div>

<!-- Sol 3: "flotar" las imágenes y dar altura al div-->
<div id="contenedor3">
    <img src="http://dummyimage.com/100x40/0ff/444&text=3A" />
    <img src="http://dummyimage.com/100x40/f4f/000&text=3B" />
</div>

<!-- Sol 4: "flotar" las imágenes y usar clear en el div-->
<div id="contenedor4">
    <img src="http://dummyimage.com/100x40/880/fff&text=4A" />
    <img src="http://dummyimage.com/100x40/44f/000&text=4B" />
</div>

<!-- Sol 5 : usar "display:flex" en el div-->
<div id="contenedor5">
    <img src="http://dummyimage.com/100x40/262/fff&text=5A" />
    <img src="http://dummyimage.com/100x40/4f0/000&text=5B" />
</div>

He colocado 6 divs. El primero de ellos (etiquetado como contenedor0) es el caso base con el espacio que queremos eliminar, y los otros cinco son las soluciones más comunes y en mi opinión más «seguras». Veamos el CSS antes de explicar cada una de ellas (los contenedores tienen dos tonos de gris alternantes para diferenciarlos):

div:nth-child(2n) { background-color:#888; }
div:nth-child(2n+1) { background-color:#777; }

#contenedor2 { font-size:0px; }

#contenedor3 { height:40px; }
#contenedor3 img { float:left; }

#contenedor4::before,
#contenedor4::after {
    clear:both;
    display:block;
    content:"";
}
#contenedor4 img { float:left; }

#contenedor5 {
    /* Modelo viejo: iOS 6, Safari 3.1-6 */
    display: -webkit-box;
    /* Modelo viejo: Firefox 19 */
    display: -moz-box;
    /* IE 10 */
    display: -ms-flexbox;
    /* Modelo nuevo - Chrome */
    display: -webkit-flex;
    /* Modelo nuevo, según especificación */
    display: flex;
}

Y así es como se ve:

Espacio entre elementos inline

Solución 1: La primera solución, aplicada en contenedor1 consiste en eliminar los espacios entre los img directamente del html. Esto es perfecto cuando son pocas imágenes y el html es simple, pero eliminar estos espacios puede hacer el código difícil de mantener. Además, esto deja el espacio debajo de las imágenes; dependiendo del layout del resto de tu HTML esto podría o no ser importante. En caso de dudas prueba la siguiente opción.

Solución 2: Creo que esta es la solución más popular, la he visto en varios foros y blogs. Consiste en simplemente asignar 0px al tamaño de fuente del div (ojo: no funciona en unidades relativas, como 0em o 0%), con lo cual los espacios también reducen su tamaño a 0px.

Esta solución también presenta algunos problemas: primero, si el tamaño de las imágenes está establecido en em tendrás que asignar a las imágenes el tamaño de fuente original para que las medidas no se vean afectadas; además en IE7 y anteriores (y en el navegador nativo Android 4.0.4) esto no funciona, por lo que tendrás que aplicar también la propiedad CSS word-spacing:-0.25em para esos navegadores. Esto último es un problema, porque para algunas fuentes el valor «exacto» será 0.26em (u otros valores): tendrás que «tantear». Personalmente recomiendo no usar esta solución.

Solución 3: Esta es una solución más segura, y consiste en flotar las imágenes dentro del div. Con esto, las imágenes se comportarán de forma similar a un elemento de bloque e ignorarán los espacios en blanco a su alrededor.

El único problema que le veo a esta solución es que debes establecer explícitamente la altura del div (40px en el ejemplo), ya que como las imágenes están «flotando» el div no las tomará en cuenta al calcular su altura. Y por supuesto, asignarle una altura al div es fácil si sabes la altura de las imágenes… pero si no conoces de antemano el tamaño de las imágenes podrías intentar la siguiente solución.

Solución 4: En este caso también aplicamos float:left a las imágenes, pero no le damos una altura específica al div. En lugar de eso usamos los pseudo-elementos ::before y ::after (en CSS3 estos dos usan dos pares de puntos en lugar de uno). En resumen (y simplificando mucho), estos dos pseudo-elementos permiten insertar «elementos virtuales» en el html de un elemento «real» desde el css (el primero justo después de la etiqueta de apertura del elemento, y el segundo antes de la etiqueta de cierre), los cuales pueden ocupar espacio y afectar a los demás elementos «reales» a su alrededor.

¿Y qué hacemos con ::before y ::after?: les asignamos una cadena vacía como contenido (estos necesitan un «algo» que insertar, aunque sea «»), los convertimos en elementos de bloque, y usamos clear:both.

El efecto de esto, es que el ::before se convierte en un elemento colocado al principio del div (antes de las imágenes) impidiendo que estas «floten» sobre él, y el ::after se convierte en un elemento colocado al final del div empujándolo hasta después de las imágenes, con lo cual se «fuerza» al div para que tenga la altura de la mayor de las imágenes. Ingenioso, ¿no?.

Solución 5: terminaremos con la solución más «elegante», que consiste en simplemente aplicar el css display:flex (con algunos prefijos para navegadores anteriores).

El funcionamiento de display:flex es largo como para explicarlo en este artículo (puedes ver aquí la especificación oficial), pero en resumen: los elementos que están dentro de un elemento con display:flex (o display:inline-flex) son tratados como «bloques flexibles» (similares a las celdas de las tablas) y permite especificar fácilmente tamaños relativos o absolutos, o dejar que determine él mismo los tamaños automáticamente.

Para nuestra solución lo importante de display:flex es que las imágenes dentro del div se mostrarán con el tamaño correcto, sin considerar los espacios en blanco, y afectarán el tamaño del div, justo como en la solución 4.

Entonces, ¿Cual solución me conviene?

Mi recomendación es la solución 5, a menos que tengas que dar soporte a navegadores (ehem…) viejos (IE soporta display:flex desde IE10). En ese caso usaría la opción 3; y si además tienes el problema de no saber la altura de las imágenes entonces no queda de otra: tendrás que probar en varios navegadores las soluciones 4, 1, y 2, en ese orden.

Espero que este artículo les haya sido de utilidad, a ni me hubiese servido de mucho hace 4 años cuando me encontré con este problema por primera vez.

Referencias

Derecho de uso

Los contenidos generados por el autor de este artículo (explicaciones, código fuente, y archivos adjuntos creados por el autor) están disponibles bajo licencia CC BY-SA 3.0, y pueden ser usados, derivados y compartidos bajo los términos indicados en la misma. Los contenidos no generados por el autor de este artículo son propiedad de sus respectivos dueños y están regidos por las licencias que estos hayan dispuesto.

Cita del día

As human beings, we have a natural compulsion to fill empty spaces.
Will Shortz

Soluciones claras y simples



Ing. Industrial, dedicado a la programación en ASP.NET+VB, SQL y Javascript+AJAX; y un poco de Android, Kotling, y Unity 🙂
Valencia, Venezuela



¿QUIERES APOYARME?

¿Te ha sido de ayuda alguno de mis artículos? Generar contenido técnico requiere de tiempo y esfuerzo. Con tu colaboración me puedes ayudar a mantener mi blog activo y actualizado. Si quieres y puedes apoyarme has clic aquí:

https://paypal.me/roimergarcia


ENTRADAS RECIENTES