Portada de UrsaKit para una guía sobre cómo centrar elementos con CSS

Cómo centrar un div en CSS depende del padre, y por eso "centrar un div" se convirtió en un chiste y CSS acabó teniendo tres formas buenas de hacerlo. Esta guía da primero la respuesta corta, después el método para cada situación y por último las trampas que explican por qué una técnica que funciona en una maquetación falla en silencio en la siguiente.

Cada ejemplo se puede pegar en el playground de CSS de UrsaKit para ver la maquetación actualizada.

01Las respuestas cortas

/* Un elemento, ambos ejes, el padre tiene altura */
.parent {
  display: grid;
  place-items: center;
}

/* Varios hijos, uno o ambos ejes */
.parent {
  display: flex;
  justify-content: center;
  align-items: center;
}

/* Un bloque con ancho, solo horizontal */
.child {
  width: min(100%, 40rem);
  margin-inline: auto;
}

Esos tres casos cubren la gran mayoría. El resto del artículo explica de qué depende cada uno.

02Flexbox: la respuesta por defecto

Flexbox reparte el espacio libre a lo largo de un eje y alinea los ítems en el otro.

.parent {
  display: flex;
  justify-content: center; /* eje principal: horizontal por defecto */
  align-items: center; /* eje cruzado: vertical por defecto */
  min-height: 100vh;
}

Dos detalles deciden si funciona:

  • El eje principal sigue a flex-direction. Con flex-direction: column, justify-content controla el eje vertical y align-items el horizontal. Leer esas propiedades como "horizontal" y "vertical" es lo que hace que el centrado parezca roto.
  • El contenedor necesita espacio libre. align-items: center reparte la altura que sobra después de los hijos. Si la altura del padre es igual a su contenido, no hay nada que repartir y el elemento se queda donde estaba.

Usa place-content: center para centrar todo el grupo.

justify-content y align-content colocan las líneas de un contenedor flex o grid. Si varios hijos deben quedarse juntos como grupo centrado en lugar de repartirse, pon place-content: center y deja align-items con su valor por defecto.

03Grid: dos líneas para los dos ejes

Grid puede centrar un hijo en ambos ejes sin que el padre sepa nada del tamaño del hijo.

.parent {
  display: grid;
  place-items: center;
  min-height: 100vh;
}

place-items: center es la abreviatura de align-items: center y justify-items: center, y funciona porque el hijo ocupa su propia área de grid en lugar de una línea flex compartida.

La abreviatura está pensada para Grid. En Flexbox justify-items no se aplica, porque los ítems del eje principal se tratan como un grupo, así que el segundo valor de place-items se ignora.

La diferencia práctica con Flexbox aparece con varios hijos:

MaquetaciónFlexboxGrid
Un hijo centradoFuncionaLo más corto
Hijos en fila, centrados como grupojustify-content: centerplace-content: center
Cada hijo centrado en su celdaIncómodoplace-items: center
Columnas de igual alturaRequiere cuidado con align-items: stretchNativo

04margin: auto

Para un elemento de bloque con un ancho menor que su contenedor, los márgenes auto reparten el espacio sobrante:

.child {
  width: min(100%, 40rem);
  margin-inline: auto;
}

Lo que sorprende es la versión vertical. En maquetación de bloque normal, los márgenes verticales auto se calculan como cero, así que margin: auto no centra un bloque en vertical:

/* NO centra en vertical: el padre no es flex ni grid */
.parent {
  height: 100vh;
}
.child {
  margin: auto;
}

/* SÍ centra en vertical: el hijo ahora es un ítem flex */
.parent {
  display: flex;
  height: 100vh;
}
.child {
  margin: auto;
}

Esto es más que una curiosidad: margin: auto en el ítem es la solución estándar al problema de desbordamiento de más abajo.

05Posicionamiento absoluto cuando no controlas el padre

Si el padre debe seguir siendo un bloque normal —un contenedor de canvas, una presentación, marcado renderizado por una biblioteca— saca el elemento del flujo:

.parent {
  position: relative;
}
.overlay {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 200px;
  height: 100px;
}

inset: 0 con margin: auto centra una caja de tamaño fijo sin conocer las dimensiones del padre. Cuando el tamaño es desconocido, la alternativa es la versión con transform:

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

El enfoque con transform saca el elemento de la maquetación del padre, así que úsalo como respaldo y no por defecto.

06Texto y contenido en línea

El contenido en línea lo centra el text-align de su padre, y el centrado vertical es otro problema:

.title {
  text-align: center;
}

.badge {
  display: grid;
  place-items: center;
  min-height: 2.5rem;
}

/* Truco heredado de una línea: solo sirve para una línea */
.button {
  line-height: 2.5rem;
  height: 2.5rem;
}

El centrado con line-height se rompe en cuanto el texto pasa a dos líneas, porque la caja de línea mantiene la altura de una mientras el contenido crece. Prefiere flex o grid en el propio elemento.

07Las trampas que rompen cada método

MétodoFalla cuandoSolución
Flexbox, ambos ejesEl contenedor no tiene altura extraAñade min-height o da altura al padre
Flexbox, ambos ejesEl hijo centrado es mayor que el contenedorUsa margin: auto en el ítem, o justify-content: safe center
justify-content con flex-direction: columnLas expectativas de eje se inviertenCambia a align-items para el eje horizontal
margin: autoEl padre es maquetación de bloque normalConvierte el padre en flex o grid
margin-inline: autoEl elemento tiene width: 100%Define un ancho máximo, por ejemplo max-width: 40rem
Absoluto + transformEl padre no está posicionadoPon position: relative en el padre
Centrado con line-heightEl texto se parte en dos líneasUsa grid o flex

Un ítem flex centrado puede esconder su propio borde superior.

Si el contenido es más alto que el contenedor y se aplica justify-content: center (o align-items: center), el desbordamiento se extiende por encima del origen de scroll y las primeras líneas dejan de ser alcanzables. Añadir margin: auto al ítem, o usar safe center, mantiene el inicio del contenido desplazable.

08Depurar un problema de centrado

  1. Mira primero la altura del padre — En el panel de maquetación de las herramientas de desarrollo, selecciona el padre. Si su altura coincide con la de su contenido, el centrado vertical no tiene con qué trabajar.
  2. Comprueba qué eje usa el padre — flex-direction: row significa que justify-content es horizontal. Cambiar a column sin tocar las propiedades es la causa más habitual de "dejó de centrarse".
  3. Busca un ancho del 100% — Un elemento que ya llena su contenedor no deja espacio libre, así que los márgenes auto no hacen nada.
  4. Prueba con contenido real, no con el estado vacío — Centra con texto realista y luego con texto que desborde, usando el playground de CSS. Casi todos los errores de centrado solo aparecen cuando el contenido crece.

Acertar con esto consiste, sobre todo, en saber qué elemento posee el espacio libre. Cuando eso queda claro, los nombres de las propiedades dejan de ser misteriosos.

09Fuentes

Preguntas frecuentes

¿Cuál es la forma más corta de centrar un elemento en ambos ejes?

Convierte el padre en contenedor grid y añade place-items: center. El elemento queda centrado en horizontal y vertical y el padre no necesita conocer su tamaño.

¿Por qué align-items: center no hace nada?

Porque el padre no tiene altura sobrante que repartir. El centrado vertical necesita una altura definida, un min-height o una línea flex/grid estirada.

¿Por qué margin: auto solo centra en horizontal?

En maquetación de bloque normal, los márgenes auto reparten el espacio inline sobrante. Para centrar en vertical con márgenes auto el elemento debe ser un ítem flex o grid, donde el eje de bloque también reparte espacio libre.

¿Por qué no puedo desplazarme hasta arriba de un elemento centrado con flex?

Cuando un ítem flex es más grande que su contenedor y se aplica justify-content: center, el desbordamiento queda por encima del origen de scroll. Usa margin: auto en el ítem o safe center.

¿place-items solo funciona en Grid?

place-items es la abreviatura de align-items y justify-items, que funcionan en Grid y parcialmente en Flexbox. En Flexbox justify-items no tiene efecto porque los ítems los reparte justify-content.

¿Sigo necesitando posición absoluta con transform?

Solo cuando el padre no puede convertirse en flex o grid, por ejemplo si lo controla una biblioteca o el elemento debe colocarse sobre un canvas.

Volver a los artículos

Artículos relacionados

Herramientas relacionadas