planeta jupiter planeta tierra

Centrar en CSS: todas las formas, de la mejor a la peor

· 8 min de lectura · CSS

Ilustración de un archivo CSS sobre fondo rosa
nave extraterrestre
Ilustración de un archivo CSS sobre fondo rosa

Centrar una caja dentro de otra fue durante años el chiste recurrente del CSS. Hoy hay una línea que lo resuelve, y otras once formas que siguen circulando por ahí. Estas son todas, ordenadas de la que envejece mejor a la que deberías borrar en cuanto la encuentres.

Antes de elegir, responde a tres preguntas

No hay una única respuesta correcta porque «centrar» son varios problemas distintos:

  • ¿Un eje o los dos? Centrar en horizontal es fácil desde siempre; el vertical es el que daba guerra.
  • ¿Un hijo o varios? Con varios entra en juego la separación entre ellos, y ahí flex y grid ganan por goleada.
  • ¿El elemento va en el flujo o superpuesto? Un modal encima de todo no se centra igual que un título dentro de una tarjeta.

Todos los ejemplos usan el mismo HTML:

<div class="caja">
    <div class="hijo">Centrado</div>
</div>

1. place-items: center — la mejor respuesta

.caja {
    display: grid;
    place-items: center;
    min-height: 300px;
}

Dos líneas, los dos ejes, sin tocar el hijo y sin importar su tamaño. Funciona igual con un hijo que con varios (se apilan centrados), no saca nada del flujo y no depende de que conozcas medidas. Si no sabes cuál usar, usa esta.

place-items es la forma corta de align-items + justify-items. Cuidado con confundirla con place-content, que centra la rejilla entera y no cada elemento dentro de su celda: con un solo hijo parecen lo mismo, con varios no.

2. Flexbox con justify-content y align-items

.caja {
    display: flex;
    justify-content: center;   /* eje principal */
    align-items: center;       /* eje cruzado */
    min-height: 300px;
}

Igual de válida y con más recorrido si vas a colocar varios elementos: tienes gap, flex-direction y el reparto del espacio sobrante. Su única pega frente a grid es que hay que recordar qué eje es cuál, y que eso cambia si giras la dirección.

Truco: place-content: center también funciona en flex, y te ahorra las dos líneas.

3. margin: auto dentro de flex o grid

.caja { display: flex; min-height: 300px; }
.hijo { margin: auto; }

Menos conocida y muy elegante: dentro de un contenedor flex o grid, margin: auto absorbe el espacio sobrante en los dos ejes. Es la solución correcta cuando el contenido puede ser más alto que la caja, porque —a diferencia de justify-content: center— no recorta el desbordamiento por arriba ni impide hacer scroll hasta él.

4. margin-inline: auto para centrar un bloque en horizontal

.hijo {
    inline-size: 40rem;
    margin-inline: auto;
}

Si solo necesitas el eje horizontal y el elemento tiene un ancho, esto es lo más simple y lo más barato: sin contenedor especial y sin cambiar el modo de layout. Es lo que hace por dentro cualquier .container de un framework.

5. text-align: center para contenido en línea

.caja { text-align: center; }

No está anticuada: es la herramienta correcta para lo que es, que es texto, iconos y cualquier contenido en línea. El error es intentar centrar con ella una caja de bloque, que es donde no hace nada.

6. align-content: center a secas

.caja {
    align-content: center;   /* sin display: flex ni grid */
    min-height: 300px;
}

Novedad reciente: los navegadores modernos aceptan align-content también en layout de bloque, así que puedes centrar en vertical sin convertir la caja en flex ni en grid, respetando el flujo normal de los hijos. Es comodísima, pero comprueba el soporte de tu público antes de usarla sin alternativa: es de 2024 y todavía no está en todos los navegadores en uso.

7. Absoluto con inset: 0 y margin: auto

.caja { position: relative; min-height: 300px; }
.hijo {
    position: absolute;
    inset: 0;
    margin: auto;
    inline-size: 12rem;
    block-size: 6rem;
}

Correcta y muy sólida cuando necesitas superponer, con una condición: el hijo debe tener tamaño propio. Al estar fuera del flujo, no empuja a nada y la caja no crece con él, así que reserva tú el alto.

8. Absoluto con translate(-50%, -50%)

.hijo {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

El clásico de mil tutoriales. Sigue siendo útil porque no necesita conocer el tamaño del hijo, pero tiene dos peajes: el elemento sale del flujo y, si sus medidas dan un número impar, acaba a medio píxel y el texto se ve ligeramente borroso en pantallas normales. Úsala solo cuando ya estabas posicionando de forma absoluta por otro motivo.

9. line-height igual a la altura

.caja { block-size: 3rem; line-height: 3rem; }

Vale exclusivamente para una línea de texto: botones pequeños, chips, insignias. En cuanto el texto pasa a dos líneas, el resultado se rompe de forma llamativa. No es un truco sucio, es una herramienta con un caso de uso muy estrecho.

10. display: table-cell con vertical-align: middle

.caja { display: table; inline-size: 100%; block-size: 300px; }
.hijo { display: table-cell; vertical-align: middle; text-align: center; }

Funciona en todas partes y fue la respuesta correcta durante la época del IE, pero hoy te obliga a envolver de más, arrastra comportamientos de tabla que no quieres (anchos que se reparten solos) y no admite gap. Si lo encuentras en un proyecto, es candidato a sustituirse por el punto 1.

11. Cálculos a mano con calc()

.hijo {
    position: absolute;
    top: calc(50% - 60px);    /* la mitad del alto del hijo... si no cambia nunca */
    left: calc(50% - 100px);
}

Depende de que las medidas del hijo no cambien jamás: ni por el idioma, ni por el tamaño de fuente del usuario, ni por un texto más largo. Es una bomba de relojería con aspecto de solución.

12. Padding y márgenes «a ojo»

.hijo { margin-top: 137px; }   /* ¿por qué 137? nadie lo sabe */

El número mágico. Funciona en tu pantalla, con ese texto y en ese navegador. Cualquier cambio lo rompe y nadie —tú incluido— sabrá de dónde salió esa cifra. Si ves uno, casi siempre se sustituye por el punto 1 o el 4.

Fuera de la lista: lo que ya no existe

<center> y el atributo align="center" están obsoletos desde HTML5: mezclan presentación con estructura y algún día dejarán de funcionar. Y vertical-align: middle sobre un elemento de bloque no centra nada, por mucho que su nombre lo prometa: solo actúa sobre contenido en línea y celdas de tabla.

La chuleta

Caso Solución
Un hijo, los dos ejes display: grid; place-items: center
Varios hijos con separación display: flex + gap + centrado
El contenido puede desbordar margin: auto en el hijo
Solo horizontal, con ancho fijo margin-inline: auto
Texto e iconos en línea text-align: center
Superpuesto (modal, badge) position: absolute + inset: 0 + margin: auto
Una sola línea de texto line-height = altura

Lo que se rompe si no lo sabes

  • Sin altura no hay centrado vertical. align-items: center no hace nada si la caja mide exactamente lo que su contenido. Dale min-height, o hazla crecer con su rejilla.
  • La cadena de height: 100%. Para que un hijo ocupe el alto de la ventana, todos sus antepasados necesitan altura. Con 100dvh o min-height: 100vh en el contenedor te ahorras la cadena entera.
  • justify-content: center corta lo que desborda. Si el contenido es más alto que la caja, el trozo de arriba queda inalcanzable incluso con scroll. Ahí es donde entra margin: auto.
  • place-items no es place-content. El primero centra cada elemento en su celda; el segundo, la rejilla entera dentro del contenedor.
  • Centrar texto largo se lee peor. El ojo pierde el inicio de cada línea: centra titulares, no párrafos.
  • El centrado también se hereda. Un text-align: center en un contenedor grande acaba afectando a media página; ponlo lo más cerca posible de lo que quieres centrar.

Y ya está

En 2026 centrar es una línea: display: grid; place-items: center. Todo lo demás de esta lista tiene su momento —varios hijos, superposición, una sola línea de texto—, y las últimas posiciones existen solo para que las reconozcas cuando aparezcan en un proyecto viejo y sepas por qué cambiarlas.

← Volver al blog

Mi hija de 11 años me ayudó a crear el diseño de este portfolio.