El box model y la propiedad box-sizing

Composición artística con cajas
Imagen de Carsten ten Brink.

El box model, o modelo de cajas, es uno de los pilares básicos para comprender el funcionamiento de CSS. Suele traer de cabeza a los que se inician con las hojas de estilo en cascada, y en ocasiones también a los no tan iniciados. Su entendimiento es la base para conseguir un layout sólido, sin miedo alguno a que en algún punto este se rompa.

Con el tiempo el box model se ha ido quedando un poco desactualizado, y lo que antes era sólo una cuestión de entendimiento y unos pocos cálculos, con los layouts actuales se ha ido convirtiendo en una auténtica pesadilla. De ahí, que en CSS3 se incluyera la propiedad box-sizing, que nos permite cambiar la forma en que se calculan las dimensiones de las cajas y nos hace la vida mucho más sencilla.

¿Qué es una caja?

En HTML todos los elementos generan una caja que los contiene y sobre esta actúan los estilos que damos con CSS. Cada caja tiene una particularidad, en función del tipo de elemento que sea (generalmente son elementos en línea o de bloque), lo que redunda en como se relaciona con otros elementos.

Una caja se define mediante las propiedades width, height, padding, border y margin. En conjunto conforman el box model o modelo de caja.

Calculando las dimensiones de una caja

Por defecto, el ancho de una caja se calcula mediante la suma de width, padding horizontal y border horizontal. Para el alto haríamos lo mismo, pero con height y la suma de los valores verticales. También hay que tener en cuenta el margin respecto al espacio que dicha caja ocupa en el documento, aunque realmente no compute para el cálculo del ancho o alto de la caja.

Así, si por ejemplo le damos a una caja un width de 30em y un height de 20em, con un padding de 2em y un border de 0.1em, la anchura de la caja es 30 + 0.1 + 2 + 2 + 0.1 = 34.2em y no 30em que es lo que declaramos como ancho para la caja con la propiedad width. De la misma forma calculamos el alto de la caja que nos da 24.2em y no 20em.

Este es el modelo de caja tradicional, donde lo que definimos con width y height es el espacio reservado para el contenido, y todos los demás valores se añaden a él para conformar el tamaño final de la caja generada. Es todo una cuestión de estandarización, pues así se acordó en el documento de la W3C Box model, para que todos los navegadores calculasen los tamaños de las cajas de la misma forma. Aunque como siempre en esto de las estandarizaciones hay alguna oveja negra, en este caso Microsoft y sus Ies.

No tiene por qué gustarte, de hecho hay bastantes detractores, pero así es el box model y con él se ha trabajado durante años. Por suerte hay forma de cambiarlo, mediante la propiedad box-sizing. Y digo por suerte, porque cuando trabajábamos con layouts fijos, sólo era cuestión de entender bien el box model y realizar unos pocos cálculos, para que todo saliese tal y como esperábamos. Sin embargo con los layouts de hoy en día, donde todas la medias son relativas y se trabaja mucho con porcentajes, la cosa no es tan sencilla.

Cierto que se puede hacer un layout responsive con el modelo de cajas tradicional, pero en ese caso todas la medidas deben ir en porcentajes, y hay que hacer muy bien los cálculos sin dejarnos nada, o al final en algún punto, se romperá. Y esto puede que sea un gusto personal, pero a mí no me entusiasma para nada dar el valor de un borde en porcentaje. Me gusta que los bordes tengan siempre el mismo tamaño, y no que se vean o muy finos en dispositivos pequeños o muy gruesos para tamaños de pantalla grandes, con lo cual lo mejor es cambiar el modelo de caja.

Box-sizing: cambiando el modelo de caja

La propiedad box-sizing nos permite cambiar el modelo de caja tradicional, y se puede declarar para cualquier elemento que soporte las propiedades width y height. Ah, por cierto, no se hereda.

Tiene cuatro valores posibles:

  • content-box: Es el valor por defecto, vamos el modelo de caja tradicional. El borde y margen interior (padding) se dibujan por fuera del alto y ancho de la caja (se suman).
  • padding-box: El margen interior, relleno o padding se dibuja dentro. Esto significa que el padding no modifica el tamaño de la caja, por contra resta el espacio disponible para el contenido. El espacio para el contenido es el alto y ancho menos el paddind. Actualmente no está soportada por ningún navegador, aunque sí en algunas versiones anteriores de Firefox.
  • border-box: El relleno y el borde se dibujan dentro del alto y del ancho. Con lo cual para calcular el tamaño disponible para el contenido dentro de la caja deberemos restar border y padding de widht y height. Lo realmente interesante es que ahora el borde y el relleno no modifican el tamaño de la caja.
  • inherit: El elemento toma el valor de box-sizing declarado en su padre o ancestro más próximo.

Usando box-sizing

Generalmente cuando usamos box-sizing queremos hacerlo para todo el documento, lo cual nos lleva ha realizar algún tipo de "reset". El primer reset para usar esta propiedad es así de sencillo:


* {
    box-sizing: border-box;
}

Funciona bastante bien, pero no tener en cuenta los pesudoelementos puede darnos alguna que otra sorpresa desagradable. Así que no tardó en aparecer una versión actualizada de este reset:


*, *:before, *:after {
    box-sizing: border-box;
}

Es otro buen reset, pero el uso del selector * complica el cambio del modelo de caja a content-box o padding-box en algún punto del CSS. Lo que nos lleva a este último reset, que se apoya en la herencia para cambiar el modelo de caja en todo el documento, lo que también facilita posibles cambios en puntos concretos:


html {
    box-sizing: border-box;
}
*, *:before, *:after {
    box-sizing: inherit;
}

Como bien te podrás imaginar, estos reset no me los he inventado yo, me los han chivado en CSS-Tricks, en un artículo de Marie Mosley dedicado a Box Sizing.