Ir al contenido
wannacode

El modelo de caja

En resumen: El modelo de caja dice que cada elemento es una caja de contenido, relleno, borde y margen; con box-sizing: border-box el ancho incluye el relleno y el borde.

Problema

Las tarjetas se salen de la pantalla

La página de los panes en un teléfono de 360px de ancho. Cada tarjeta tiene width: 100%: tan ancha como la columna. Aun así, las tarjetas se salen por la derecha, y toda la página se desplaza hacia el lado.

HTML, CSS, JS

La columna mide 360 − 2 × 16 = 328px. La tarjeta debía medir eso, y mide 362px: 34px más que la columna. Esos 34px no son un error del número 100%. Están en lo que mide width.

La idea

Cuatro capas

Para CSS, cada elemento es una caja rectangular. Tiene cuatro capas, de dentro hacia fuera:

  • el contenido: el texto, la imagen, los hijos;
  • padding (relleno): el espacio entre el contenido y el borde. El fondo del elemento lo rellena;
  • border (borde): el marco;
  • margin (margen): el espacio fuera del borde, hasta las cajas vecinas. Es transparente.

Por defecto width es solo el ancho del contenido. El relleno y el borde se suman por fuera, a ambos lados:

.card {
width: 100%; /* 328px: el contenido */
padding: 16px; /* + 2 × 16 */
border: 1px solid #ccc; /* + 2 × 1 = 362px */
}

Por eso la tarjeta del principio mide 362px. padding: 16px vale para los cuatro lados. También puedes fijarlos por separado: padding: 8px 16px (arriba y abajo, izquierda y derecha) o padding-left: 16px.

Míralo

Mira la caja

La caja se construye capa por capa. La línea de arriba es width: fíjate en lo que mide.

/* por defecto: box-sizing: content-box */
.card {
width: 280px;
padding: 24px;
border: 8px solid #2b3a55;
margin: 16px;
}
.card.bb {
box-sizing: border-box;
}
Paso a paso, en palabras
  1. En el centro está el contenido: el texto de la tarjeta. Por defecto width es solo el ancho del contenido: 280px.
  2. padding es el espacio entre el contenido y el borde. Está a ambos lados: 280 + 2 × 24 = 328px. El fondo de la tarjeta también lo rellena.
  3. border es el marco, también a ambos lados. La caja ya mide 344px, no 280: width no decía cuánto mide la tarjeta en la pantalla.
  4. margin es el espacio fuera del borde, entre esta caja y la siguiente. No tiene fondo y no es parte de la tarjeta, pero ocupa sitio: 376px.
  5. box-sizing: border-box cambia lo que significa width: ahora es el ancho hasta el borde. La tarjeta mide 280px, y el contenido se encoge a 280 − 48 − 16 = 216px.
  6. El mismo CSS, dos significados de width. Con content-box la tarjeta mide 344px; con border-box, 280px: lo que dice width. Por eso casi todos los proyectos ponen border-box en todos los elementos.

Las mismas dos tarjetas en el navegador. Lo azul es el párrafo de dentro: mide lo que el contenido de la tarjeta. En las herramientas de desarrollo (F12) selecciona la tarjeta: el panel Calculado dibuja la misma caja con los números de cada capa.

HTML, CSS, JS

La idea

box-sizing: border-box

Hacer cuentas de cabeza genera errores: quieres una tarjeta tan ancha como la columna y tienes que restar el relleno y el borde. box-sizing: border-box cambia lo que significa width: es el ancho hasta el borde, incluido. El relleno y el borde se restan por dentro, y el contenido se encoge.

Entonces width: 100% es de verdad la columna, sea cual sea el relleno. Por eso casi todos los proyectos empiezan con:

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

* alcanza a todos los elementos. box-sizing no se hereda, así que la regla es para todos los elementos, no solo para <html>. ::before y ::after son trozos de contenido que CSS añade por sí mismo; también son cajas.

Pruébalo

Haz que quepan las tarjetas

Haz que las tarjetas quepan en la pantalla del teléfono con box-sizing: border-box. El relleno (16px) y el borde (1px) se quedan.

HTML, CSS, JS

La regla con la que empiezan casi todos los proyectos:

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

La idea

Los márgenes se fusionan

Dos cajas, una debajo de la otra: el margen inferior de la de arriba y el margen superior de la de abajo no se suman. Se fusionan, y se queda el mayor.

HTML, CSS, JS
  • Las notas tienen 24px debajo y 16px encima. Entre ellas hay 24px, no 40px.
  • El encabezado del banner tiene margin: 20px 0. El banner no tiene relleno ni borde arriba, así que el margen del encabezado sale por encima: el fondo naranja empieza justo encima del texto. Con padding: 1px 16px en el banner, el fondo cubre también el margen.

Solo se fusionan los márgenes verticales. A izquierda y derecha siempre se suman. En flex y grid, las próximas lecciones, ni siquiera los verticales se fusionan.

La idea

block, inline e inline-block

No todas las cajas se comportan igual. La propiedad display dice cómo se coloca una caja entre las demás.

  • block: empieza en una línea nueva y ocupa todo el ancho de su padre. El ancho, el alto, el margen y el relleno se aplican. div, p, h1 y article son así.
  • inline: se coloca dentro de la línea de texto y mide lo que su contenido. El ancho y el alto no se aplican, un margen vertical no mueve nada, y un relleno vertical se pinta, pero no separa las líneas. span, a y strong son así.
  • inline-block: se coloca en la línea como inline, pero el ancho, el alto, el margen y el relleno se aplican como en block.
HTML, CSS, JS

Las dos etiquetas tienen las mismas propiedades, y la segunda es además inline-block. La primera es inline: width: 64px y el margen no se aplican, y el rojo del relleno sobresale por encima y por debajo de la línea sin separarla de las demás. La segunda es inline-block: mide 64 + 2 × 8 = 80px de ancho (aquí sigue siendo content-box), y el párrafo se hace más alto para que quepa.

Pruébalo

Las etiquetas

Las etiquetas −20% y Nuevo deben medir 64px de ancho cada una y estar una al lado de la otra en una línea. Ahora mismo el ancho no se aplica.

HTML, CSS, JS

La idea

Unidades

Hasta ahora todo estaba en px. CSS tiene también otras unidades, y cada una sirve para algo:

  • px: una medida fija. Buena para bordes y huecos pequeños.
  • rem: el tamaño de fuente de <html> (16px, salvo que alguien lo haya cambiado). 1.5rem son 24px en toda la página. Si una persona agrandó la fuente en los ajustes del navegador, rem crece con ella y px no. Por eso las fuentes y los espacios van mejor en rem.
  • em: el tamaño de fuente del propio elemento; en font-size, el del padre. Un relleno en em crece con el texto de un botón.
  • %: del padre. width: 50% es la mitad del ancho del contenido del padre.
  • vw y vh: el 1% del ancho y del alto de la ventana.
HTML, CSS, JS

El encabezado mide 1.5rem = 24px. La tarjeta es el 50% de 320px = 160px. Su fuente es de 18px, así que padding: 1em son 18px. 1.25rem en el encabezado de la tarjeta son 20px: a rem no le importan los 18px de la tarjeta. 0.75em en <small> viene de la fuente del párrafo, que heredó 18px: 13,5px.

Pruébalo

Encuentra el error

El menú mide 20px, el submenú de dentro, 25px, y el siguiente nivel es aún mayor. ¿Qué línea tiene la culpa?

Elige la línea con el error.

Más precisamente, para curiosos

Los porcentajes en padding y margin salen del ancho del padre, también arriba y abajo. padding-top: 50% hace una caja de la mitad de alto que de ancho es su padre.

100vw y la barra de desplazamiento. vw incluye la barra de desplazamiento. Si la página tiene una barra vertical visible, un elemento con width: 100vw es más ancho que la página y provoca un desplazamiento horizontal. Para «todo el ancho», width: 100% es más seguro.

vh en el teléfono. La barra de direcciones aparece y desaparece. 100vh es la altura con la barra oculta, así que, cuando la barra se ve, el borde inferior queda por debajo de la pantalla. 100dvh sigue la altura real en cada momento.

outline se dibuja como un borde, pero no ocupa espacio y no mueve nada. Por eso el foco de los botones se muestra con él.

min-width y max-width ponen límites: max-width: 100% evita que una imagen se salga de la columna.

Formularios. En Chromium los botones son border-box por defecto, mientras que los campos (input) son content-box. La regla con * los iguala.

Cómo evitar la fusión. El margen de un hijo no sale a través del padre si el padre tiene relleno o borde arriba, o si es display: flow-root. Así el padre crea un contexto de maquetación nuevo (block formatting context).

Un margen negativo tira de la caja hacia fuera y la superpone a sus vecinas. Rara vez lo necesitas.

Ejercicio

El catálogo en el teléfono

El catálogo en un teléfono (360px). Pon border-box en todos los elementos para que las tarjetas quepan en la pantalla. La tarjeta: padding 1rem, un borde 1px solid #ddd y 12px de espacio debajo de cada una. Los encabezados de los productos miden 1.25rem. Las etiquetas −20% y Nuevo son inline-block, con padding 2px 8px, texto blanco y fondo rojo (#c0392b). El botón mide lo que el interior de la tarjeta: width: 100%.

HTML, CSS, JS

Test

Ponte a prueba

1. .box { width: 200px; padding: 10px; border: 2px solid; } sin box-sizing. ¿Cuánto mide de ancho la caja en la pantalla?
2. La misma regla con box-sizing: border-box. ¿Cuánto mide de ancho el contenido?
3. Un párrafo tiene margin-bottom: 30px y el siguiente tiene margin-top: 20px. ¿Qué distancia hay entre ellos?
4. <html> tiene 16px y el elemento padre, 20px. ¿Cuánto es font-size: 1.5rem en el hijo?
5. ¿Por qué width: 80px no hace nada en un <span>?

Creado por Ivo Gergov como parte de la campaña de Evo Tech por una educación accesible en programación ·