Desde hace ya algunos años, una de las técnicas más usadas en las Hojas de Estilo en Cascada (CSS) para maquetar en sitios web que deban mostrar elementos de tipo bloque en línea es la de establecer su regla “display” con el valor “inline-block”. El uso de “display: inline-block;” nos permite realizar menús, muestras de elementos, etc, sin necesidad de recurrir a elementos flotantes con la regla “float” que ya se encuentra desaconsejada salvo necesidad expresa o la muy mala práctica de maquetación consistente en usar tablas para distribuir el contenido. Así pues, en este artículo os expongo el problema y varias soluciones en mayor o menos medida recomendadas puesto que algunas las considero malas prácticas y otras son algo “raras”, pero sin duda, al final del artículo encontraréis la que a mi parecer es la forma correcta de realizar este tipo de maquetado. Podéis descargaros el website de ejemplo para seguir el artículo desde este enlace.
Bien, veamos un ejemplo en el que queremos mostrar un menú de elementos en línea
<nav class="mainNav">
<div class="navItem">Item 1</div>
<div class="navItem">Item 2</div>
<div class="navItem">Item 3</div>
<div class="navItem">Item 4</div>
</nav>
Y añadimos un poco de estilos CSS
nav.mainNav {
display: inline-block;
margin: 20px;
padding: 20px;
border: 1px solid #4800ff;
}
nav.mainNav > .navItem {
display: inline-block;
padding: 20px;
background: #4800ff;
color: #fff;
}
Esto nos producirá la siguiente salida
Como se puede apreciar, existe un espacio entre los elementos que realmente no existe ni en HTML, ni en CSS, “ni por el propio navegador”… lo que puede producirnos un problema si queremos que los elementos aparezcan completamente juntos. ¿Cómo lo solucionamos?
Solución 1: Minimizando el HTML
Si minimizamos el HTML eliminando el espacio entre los elementos que queremos mostrar en línea “inline-block”, es decir, si los mostramos en una línea sin espacio o salto de línea entre ellos… misteriosamente se soluciona el problema. Aquí tenemos el ejemplo y su resultado
<nav class="mainNav">
<div class="navItem">Item 1</div><div class="navItem">Item 2</div><div class="navItem">Item 3</div><div class="navItem">Item 4</div>
</nav>
También podemos usar algunos trucos muy feos como cerrar el elemento en la siguiente línea o usar comentarios en los saltos de línea tal y como os muestro más abajo
<nav class="mainNav">
<div class="navItem">Item 1</div
><div class="navItem">Item 2</div
><div class="navItem">Item 3</div
><div class="navItem">Item 4</div>
</nav>
<nav class="mainNav">
<div class="navItem">Item 1</div><!--
--><div class="navItem">Item 2</div><!--
--><div class="navItem">Item 3</div><!--
--><div class="navItem">Item 4</div>
</nav>
Estos trucos nos funcionarán sin problemas aunque, para ser sinceros me quedo con el tercero por ser menos “raro”.
Solución 2: Ajustar márgenes (negativos)
La siguiente solución pasa por ajustar los márgenes entre los elementos. Después de indagar y probar, resulta que el margen que se añade en los lados de los elementos es de 4px y sólo necesitaríamos restarlos. En el ejemplo, añadiré una nueva clase a los elementos sobre la que aplicaré el arreglo.
<nav id="mainNav">
<div class="navItem navItemSolution2">Item 1</div>
<div class="navItem navItemSolution2">Item 2</div>
<div class="navItem navItemSolution2">Item 3</div>
<div class="navItem navItemSolution2">Item 4</div>
</nav>
nav#mainNav {
display: inline-block;
margin: 20px;
padding: 20px;
border: 1px solid #4800ff;
}
nav#mainNav > .navItem {
display: inline-block;
padding: 20px;
background: #4800ff;
color: #fff;
}
nav#mainNav > .navItemSolution2{
margin: 0 -4px;
}
Esta solución podría es tar bien pero… ¿y si mañana cambian las interpretaciones en algún navegador? ¿Se seguirá mostrando bien? Pues… podría darnos muchos problemas puesto que habría que reescribir nuestras hojas de estilo.
Solución 3: Ajustar fuente
Otra posible solución, dado que lo que se añade podría equivaler a un espacio de texto…, pasa por ajustar el tamaño de fuente, poniéndolo a 0px en el contenedor y estableciendo el correcto en los propios elementos en línea tal y como os muestro más abajo. Nuevamente jugaré con las clases de los elementos para no tener que reescribir todo.
<nav class="mainNav mainNavSolution3">
<div class="navItem navItemSolution3">Item 1</div>
<div class="navItem navItemSolution3">Item 2</div>
<div class="navItem navItemSolution3">Item 3</div>
<div class="navItem navItemSolution3">Item 4</div>
</nav>
nav.mainNav {
display: inline-block;
margin: 20px;
padding: 20px;
border: 1px solid #4800ff;
}
nav.mainNavSolution3 {
font-size: 0;
}
nav.mainNav > .navItem {
display: inline-block;
padding: 20px;
background: #4800ff;
color: #fff;
}
nav.mainNav > .navItemSolution3 {
font-size: 16px;
}
Como podéis ver, esta solución tampoco es nada buena puesto que nuevamente podemos enfrentarnos a problemas si mañana tenemos que actualizar nuestras hojas de estilo.
Solución 4: Flotar los elementos con float (volver al pasado y a sus horrores)
La siguiente solución pasa por poner los elementos como flotantes, con lo que estaríamos volviendo al pasado y a los problemas de que salten de línea, o que no se ajuste el contenido que se encuentra bajo él, al uso de elementos con “clear:both” para corregir problemas y a veces crear otros…, pero bueno, aquí tenéis el ejemplo.
<nav class="mainNav">
<h2>Elementos flotantes</h2>
<div class="navItem navItemSolution4">Item 1</div>
<div class="navItem navItemSolution4">Item 2</div>
<div class="navItem navItemSolution4">Item 3</div>
<div class="navItem navItemSolution4">Item 4</div>
</nav>
nav.mainNav {
display: inline-block;
margin: 20px;
padding: 20px;
border: 1px solid #4800ff;
}
nav.mainNav > .navItem {
display: inline-block;
padding: 20px;
background: #4800ff;
color: #fff;
}
nav.mainNav > .navItemSolution4{
float: left;
}
Como podéis observar funciona perfectamente pero, por favor, no viváis del pasado y mantened las cosas más simples, así que olvidad los elementos flotantes salvo que sea estrictamente necesario (K.I.S.S.). Hay soluciones mucho mejores como la que os pongo al final del artículo.
Solución 5: No cerrar los elementos en línea… (MUY MUY MALA PRÁCTICA)
La característica de HTML5 que permite no cerrar los elementos es algo que siempre me ha chirriado y dolido en el alma y provoca problemas como uno que me encontré hace no mucho en un mega-producto de una gran compañía (a Alberto Díaz y a Adrían Díaz les sonará), pero si sois amantes de esta práctica (espero con el corazón que no haya nadie), esta solución os puede valer.
<nav class="mainNav">
<h2>No cerrar elementos</h2>
<ul>
<li>Item 1
<li>Item 2
<li>Item 3
<li>Item 4
</ul>
</nav>
nav.mainNav {
display: inline-block;
margin: 20px;
padding: 20px;
vertical-align: top;
border: 1px solid #4800ff;
}
nav.mainNav > ul {
margin: 0;
padding: 0;
}
nav.mainNav > ul > li {
display: inline-block;
padding: 20px;
background: #4800ff;
color: #fff;
}
No quiero ser pesado pero… esta me parece una muy mala práctica.
Solución 6: Usar modelo de caja flexible (Mi recomendación)
Otro día hablaré más a fondo de este modelo que es una gozada para maquetar y para modelar nuestros sitios responsivos (responsive web design). Esta característica es una de las más potentes porque permite jugar mucho con el modelado de los elementos, su comportamiento, etc etc y es muy simple de usar como podréis observar.
<h2> Modelo de caja flexible</h2>
<nav class="mainNav flexbox">
<div class="navItem flex-item">Item 1</div>
<div class="navItem flex-item">Item 2</div>
<div class="navItem flex-item">Item 3</div>
<div class="navItem flex-item">Item 4</div>
</nav>
nav.mainNav {
display: inline-block;
margin: 20px;
padding: 20px;
vertical-align: top;
border: 1px solid #4800ff;
}
nav.mainNav.flexbox {
/* BROWSER DEFINITION */
display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */
display: -ms-flexbox; /* TWEENER - IE 10 */
display: -webkit-flex; /* NEW - Chrome */
/* W3C DEFINITION */
display: flex;
display: inline-flex;
}
nav.mainNav > .navItem {
display: inline-block;
padding: 20px;
background: #4800ff;
color: #fff;
}
Se puede usar tanto “display: flex” como “display: inline-flex” para el contenedor para poder así controlar el modelado dentro de la página (en bloque o en línea). Los elementos que contenga el contenedor al que le apliquemos una de estas propiedades, automáticamente pasarán a comportarse como elementos de caja flexible, adaptándose a la perfección a nuestras necesidades. Si queréis saber más sobre el modelo de caja flexible (flexbox) podéis esperar a que escriba un artículo sobre ello o simplemente consultar este artículo de la MSDN
NOTA: Tened mucho cuidado con Safari porque aún parece que no se ha subido al carro de las especificaciones de W3C