Este post viene a raíz de una pregunta que recibí hace unos días. La cuestión era similar a la siguiente:
Tengo una página que, básicamente, consta de una cabecera, un cuerpo principal con contenido, y un pie de página.
En la parte central tengo necesidad de introducir una aplicación de foros que tengo que mostrar mediante un iframe.
Lo que me gustaría es que esa parte central ocupase siempre todo el espacio disponible entre la cabecera y el pie.
Si le pongo un 100% al div del contenido principal no me funciona y de hecho es bastante más grande que la altura
disponible.
¿Cómo puedo conseguir esto?
Es un caso muy típico de maquetación.
Lo ilustro mejor con una figura:
En este ejemplo lo que he hecho es poner una cabecera y un pie, y entre ambos ocupando todo el espacio disponible, mi blog embebido en un iframe.
Esta zona central debe adaptar su tamaño automáticamente y en tiempo real al espacio disponible incluso si cambiamos las dimensiones de la ventana.
¿Cómo lo conseguimos?
La manera clásica de conseguir algo como esto sería usando tablas, una estructura de este estilo:
1: <table width="100%" height="100%" cellpadding="0" cellspacing="0">
2: <tr>
3: <td>Cabecera</td>
4: </tr>
5: <tr height="100%">
6: <td><iframe height="100%" width="100%"></iframe></td>
7: </tr>
8: <tr>
9: <td>Pie</td>
10: </tr>
11: </table>
Con esto conseguiríamos la distribución deseada. La tabla ocupa todo el espacio disponible en la ventana con su ancho y alto al 100%, las filas superior e inferior ocupan lo que sea necesario para mostrar su contenido, y la fila del medio (que tiene una altura del 100% respecto a la tabla) crece hasta ocupar el espacio restante en vertical.
Sin embargo esta solución no es adecuada para las necesidades de las webs actuales. El motivo es que no deben usarse tablas ni otros elementos con el mero objetivo de definir la parte visual de una página. La web semántica y HTML5 promueven la separación completa del contenido y su representación visual, la cual dependerá de las reglas CSS que se definan y se apliquen sobre el contenido.
En el ejemplo de código anterior el único objetivo de introducir la tabla es el de definir la distribución que tendrá la página. Además se indican sus dimensiones con atributos, otra mala práctica y de hecho está obsoleta en HTML5. Además no se trata de una solución aconsejable desde el punto de vista de la accesibilidad de los contenidos, algo muy importante en muchas webs. Las tablas son únicamente para mostrar datos. Punto.
Lo que deberíamos tener es una distribución de contenidos como esta:
1: <div id="contenido">
2: <div id="cabecera">
3: Cabecera
4: </div>
5: <div id="principal">
6: <iframe style="width:100%;height:100%;" src="http://www.jasoft.org/blog"></iframe>
7: </div>
8: <div id="pie">
9: Pie de página
10: </div>
11: </div>
Es decir, tres simples divs para marcar cada zona y, si acaso, un div contenedor de toda la página.
También podríamos haber usado etiquetas semánticas de HTML5, pero lo cierto es que al final la mayor parte de los diseñadores web usarán divs en su día a día.
La mejor opción para conseguir lo que buscamos es sacar partido a ciertos valores poco conocidos en general de la propiedad display de CSS3, soportados hoy en día por todos los navegadores (incluso por Internet Explorer a partir de la versión 7).
La propiedad CSS3 "display"
Los valores más conocidos de esta propiedad son "none" para ocultar elementos, "block" para mostrarlos como un elemento de bloque, e "inline" para que se muestre en línea.
CSS3 sin embargo introduce más de 10 valores adicionales a esta propiedad.
Los dos que nos interesan para nuestro problema concreto son "table" y "table-row".
Éstos y sus 7 valores "hermanos" (relacionados con lo mismo) surgen para poder usar las facilidades de las tablas sin necesidad de incluir marcado de tablas en el HTML, que es justo lo que queremos.
Para resolver este problema en concreto lo que tenemos que saber es que:
- display:table hace que el elemento al que se le aplique el estilo se comporte como si fuera una tabla.
- display:table-row hace que se comporte como la fila de una tabla, con lo que todo ello conlleva.
En mi curso de HTML(5) y CSS(3) en campusMVP se explican con detalle todos los valores y su funcionamiento un tanto peculiar, y también hay vídeos prácticos de maquetación de páginas usándolos (y con muchas otras técnicas de maquetación de páginas), pero para nuestro ejemplo nos llega con saber esto.
Así, lo único que tenemos que hacer es definir unas reglas CSS como las siguientes:
1: html, body {
2: height:100%;
3: width:100%;
4: margin:0;
5: }
6:
7: #contenido {
8: height:100%;
9: width:100%;
10: display:table;
11: }
12:
13: #cabecera {
14:
15: font-size:70px;
16: background-color:blue;
17: color:white;
18: display:table-row;
19: }
20:
21: #pie {
22:
23: font-size:70px;
24: background-color:red;
25: color:white;
26: display:table-row;
27: }
28:
29: #principal {
30:
31: background-color:yellow;
32: height:100%;
33: width:100%;
34: display:table-row;
35: }
Lo que he hecho es indicar que el div que contiene a todos los demás ("contenido") se comporte como una tabla. Ahora, cada uno de los divs que contiene y que van uno tras otro, indicamos mediante display:table-row que se deben comportar como filas de una tabla. Además de eso es importante indicar que el div principal es el que va a tener una altura del 100%. En este caso se refiere al 100% dentro de su contenedor que se comporta como una tabla.
Esto es equivalente a lo que haríamos antiguamente con una tabla, pero la diferencia es muy sustancial ya que ahora tenemos perfectamente separado el contenido de su representación y podríamos variarlo a voluntad tocando únicamente el CSS.
En realidad ni siquiera es necesario utilizar el elemento contenedor e indicar que se comporte como una tabla. CSS3 detecta automáticamente los elementos "virtuales" que faltan en una tabla y los introduce por nosotros, así que incluso eliminando el contenedor funcionaría bien.
Con los valores CSS de display para emular tablas podemos conseguir cosas de otra manera muy complicadas de hacer, como lo que acabo de mostrar, pero también centrar elementos dentro de otros con propiedades directas (como text-align y vertical-align) y sin necesidad de subterfugios, tener alineaciones exactas de bloques sin necesidad de flotar ni de posicionarlos, etc... Esto nos proporciona grandes ventajas a la hora de maquetar, ya que no estamos a merced de las cosas extrañas que nos pueden hacer los elementos flotados o posicionados de manera absoluta. Se nos simplifica mucho en general crear la distribución de elementos que queramos.
En mi curso online de HTML(5) y CSS(3) de campusMVP. aprenderás infinidad de cosas más relacionadas con todo esto. Si quieres aprender de verdad sobre HTML y CSS y tenerme como tutor para contestar tus dudas empieza hoy mismo.
Puedes descargar el código de este ejemplo de aquí (ZIP, 566 bytes).
¡Espero que te sea útil!