El modelo de caja

Todo elemento de HTML es una caja, y esa caja tiene cuatro capas.

Las cuatro capas, de fuera hacia adentro

flowchart TB
    subgraph MAR["margin"]
        direction TB
        subgraph BOR["border"]
            direction TB
            subgraph PAD["padding"]
                direction TB
                CON["content<br/>el texto o la imagen"]
            end
        end
    end
CapaQué es
contentEl contenido: el texto o la imagen
paddingRelleno interno: separa el contenido de su borde
borderEl borde que rodea la caja
marginEspacio externo: separa esta caja de las de al lado

La frase que hay que memorizar

padding empuja hacia adentro; margin separa hacia afuera.

Si el texto está muy pegado al borde de su tarjeta, es padding. Si dos tarjetas están muy juntas entre sí, es margin.

Cómo se escriben

.tarjeta {
  padding: 24px; /* los cuatro lados */
  padding: 16px 24px; /* arriba-abajo | izquierda-derecha */
  padding: 8px 16px 24px 32px; /* arriba | derecha | abajo | izquierda */
}

La forma de dos valores es la que más vas a usar: 16px 24px da más aire a los lados que arriba y abajo, que es como se ven bien casi todos los botones.

margin acepta exactamente los mismos formatos.

margin: 0 auto centra una caja

.contenedor {
  width: 900px;
  margin: 0 auto;
}

auto reparte el espacio sobrante en partes iguales a izquierda y derecha. Es el truco clásico para centrar un bloque, y necesita que la caja tenga un width.

El fondo cubre el padding, no el margin

Si le pones background-color a una tarjeta, el color llega hasta el borde, incluyendo todo el relleno interno. El margin queda fuera y siempre se ve del color de lo que haya detrás.

Por eso, si quieres más superficie de color, es padding; si quieres más separación entre cajas, es margin.

¿Por qué mi caja de 300 px mide 348?

.tarjeta {
  width: 300px;
  padding: 20px;
  border: 4px solid #12a5ce;
}

Abre el inspector y la tarjeta mide 348 px de ancho: los 300 del width, más 20 de padding a cada lado, más 4 de borde a cada lado. Por defecto, el width es solo el ancho del contenido, y el relleno y el borde se suman por fuera.

box-sizing: border-box cambia esa cuenta: el width pasa a ser el ancho total de la caja, y el padding y el borde se acomodan por dentro.

* {
  box-sizing: border-box;
}

El * es el selector universal: apunta a todos los elementos. Con esa regla al comienzo del archivo, una caja de 300px mide 300 px, tenga el relleno que tenga.

Pon box-sizing: border-box al inicio de tu CSS

Es la primera regla de casi todas las hojas de estilo profesionales, y hace que las medidas signifiquen lo que dicen. Tailwind la trae puesta por defecto, así que cuando llegues ahí, las cajas ya se comportan así.

Flexbox

Por defecto los elementos de bloque se apilan: cada uno ocupa una línea entera y empuja hacia abajo lo que sigue. Flexbox es la herramienta para ponerlos en fila y repartirlos.

Se activa en el contenedor, no en los hijos

display: flex se escribe en el elemento padre. Los que se acomodan son sus hijos directos, que no necesitan ninguna regla especial.

Confundir esos dos papeles es lo que más cuesta al principio: si pones display:flex en las tarjetas en vez de en la caja que las contiene, no pasa nada de lo que esperas.

<div class="contenedor">
  <div>caja A</div>
  <div>caja B</div>
  <div>caja C</div>
</div>
.contenedor {
  display: flex; /* activa Flexbox */
  flex-direction: row; /* en fila (por defecto) */
  gap: 16px; /* espacio entre los hijos */
}

Fila o columna, según flex-direction

flowchart TB
    subgraph R["row"]
        direction LR
        A1["A"] ~~~ B1["B"] ~~~ C1["C"]
    end

    subgraph C["column"]
        direction TB
        A2["A"] ~~~ B2["B"] ~~~ C2["C"]
    end

    R ~~~ C

gap en vez de márgenes uno por uno

gap: 16px pone el espacio entre los hijos, y solo entre ellos: no sobra margen al principio ni al final. Antes de que existiera había que poner margin-right a todos menos al último, y era un dolor.

Distribuir y alinear

Dos propiedades hacen casi todo el trabajo, y se reparten los dos ejes.

PropiedadReparteValores más usados
justify-contentA lo largo de la filaflex-start, center, space-between
align-itemsA lo ancho, el eje contrarioflex-start, center, stretch
Valor de justify-contentQué hace
flex-startTodos al inicio (por defecto)
centerTodos al medio
space-betweenUno a cada extremo, el sobrante repartido entre medio
Valor de align-itemsQué hace
flex-startArriba
centerAl medio
stretchTodos a la misma altura (por defecto)

La receta de una barra de navegación

.barra {
  display: flex;
  justify-content: space-between; /* marca a la izquierda, enlaces a la derecha */
  align-items: center; /* todo centrado en vertical */
  padding: 16px 24px;
}

Estas tres líneas son el 90% de las barras de navegación que existen.

Cómo recordar cuál es cuál

justify va a lo largo de la fila; align va a lo ancho.

Con flex-direction: column los ejes se dan vuelta: ahí justify-content reparte en vertical y align-items en horizontal. Por eso los nombres no dicen “horizontal” ni “vertical”.

Un ejemplo completo

<div class="precios">
  <div class="tarjeta">Básico</div>
  <div class="tarjeta">Pro</div>
  <div class="tarjeta">Full</div>
</div>
/* el contenedor */
.precios {
  display: flex;
  gap: 20px;
  align-items: stretch;
}
 
/* los hijos */
.tarjeta {
  flex: 1; /* las tres, del mismo ancho */
  background: #e2f3f9;
  padding: 24px;
  text-align: center;
}

flex: 1 va en cada hijo y es lo que reparte el ancho en partes iguales. Sin él, cada tarjeta se encoge al tamaño de su propio texto.

Pruébalo borrando una línea

Copia ese ejemplo, quítale el flex: 1 y mira qué pasa. Es la forma más rápida de entender qué hace cada propiedad: quitarla y observar.

Checkpoint

Intenta responder antes de desplegar cada pregunta.