Centrar un div en CSS: en horizontal, en vertical, con Flexbox o Grid

Tres líneas de Flexbox para centrar un div y luego cada caso por separado: horizontal, vertical, toda la página, imagen, texto y botón. Con la alternativa Grid, el método position absolute y los errores que impiden el centrado.

Centrar elementos en CSS con Flexbox: horizontal y vertical
Respuesta rápida

Para centrar un div en su contenedor, dale al contenedor display: flex; justify-content: center; align-items: center;. justify-content centra en horizontal y align-items en vertical. Si el centrado vertical no se ve, es que el contenedor no tiene altura: añade min-height: 100vh para toda la página, o una altura explícita.

Centrar un div en CSS exigió trucos durante mucho tiempo. Ya no: tres líneas de Flexbox centran cualquier elemento dentro de su contenedor, en horizontal y en vertical. Este artículo empieza por esa respuesta corta y luego detalla cada situación, desde centrar una imagen hasta centrar un botón, con la alternativa de Grid y los errores que hacen creer que «no funciona».

La respuesta corta

css
.conteneur {
  display: flex;
  justify-content: center; /* horizontal */
  align-items: center;     /* vertical */
}
html
<div class="conteneur">
  <div class="boite">Je suis centrée</div>
</div>

Las dos propiedades se aplican al padre, nunca al elemento que quieres centrar. Y el centrado vertical solo se ve si el padre tiene más altura que su contenido: es lo primero que hay que comprobar cuando nada se mueve.

Centrar en horizontal

Con Flexbox

justify-content reparte los hijos a lo largo del eje principal, horizontal por defecto. center los agrupa en el medio.

css
.conteneur {
  display: flex;
  justify-content: center;
  gap: 1rem; /* espacio entre varios hijos centrados */
}

Con varios hijos, se quedan uno al lado del otro y centrados como grupo. Es el caso de los dos párrafos o de las dos imágenes del ejemplo histórico de este artículo.

Con margin auto

Sin Flexbox, un bloque de anchura conocida se centra con márgenes automáticos:

css
.boite {
  width: 320px;      /* o max-width: imprescindible */
  margin: 0 auto;
}

Sin width ni max-width, la caja ocupa todo el ancho disponible y los márgenes automáticos valen cero. Es el método que hay que recordar para centrar una columna de contenido en una página.

Con text-align

text-align: center centra el contenido en línea de un bloque: texto, un enlace, una imagen inline. No centra el bloque en sí dentro de su padre.

css
.titre {
  text-align: center; /* centra el texto dentro de .titre */
}

Centrar en vertical

align-items gobierna el eje transversal, vertical por defecto. El contenedor debe tener altura para que el centrado se vea.

css
.conteneur {
  display: flex;
  align-items: center;
  height: 300px;
}

Para centrar en vertical un solo hijo y dejar los demás arriba, align-self se aplica a ese hijo:

css
.conteneur .dernier {
  align-self: center;
}

Otra forma de escribirlo, a menudo más corta: margin: auto en el hijo de un contenedor flex lo centra en las dos direcciones, absorbiendo todo el espacio libre.

css
.conteneur { display: flex; height: 300px; }
.boite     { margin: auto; }

Centrar en toda la página

Una pantalla de acceso, un mensaje de error, una página de espera: el elemento tiene que quedar en el centro de la ventana. El contenedor ocupa toda la altura visible con min-height: 100vh.

css
body {
  margin: 0;
}

.page {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh; /* 100 % de la altura de la ventana */
}

min-height mejor que height: si el contenido desborda la ventana en una pantalla pequeña, el contenedor crece en lugar de cortar. En móvil, 100dvh (altura dinámica, que tiene en cuenta las barras del navegador) es aún más preciso y lo admiten los navegadores actuales.

Centrar una imagen

Una imagen es un elemento en línea: dentro de un bloque, text-align: center en el padre la centra en horizontal. Para centrarla en los dos sentidos, o dentro de un marco de tamaño fijo, Flexbox es más sencillo.

css
/* Solo horizontal */
figure {
  text-align: center;
}

/* Horizontal y vertical, en una miniatura cuadrada */
.vignette {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 200px;
  height: 200px;
  overflow: hidden;
}

.vignette img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

Una imagen sola en una columna también se centra como bloque: display: block; margin: 0 auto; con una anchura o una anchura máxima.

Centrar un texto y un botón

Un texto se centra con text-align: center en su bloque. Un botón es un elemento inline-block: la misma propiedad en su padre lo centra en horizontal.

css
.actions {
  text-align: center;
}

/* Para centrar varios botones con un espaciado regular */
.actions {
  display: flex;
  justify-content: center;
  gap: 0.75rem;
}

Para centrar el texto dentro de un botón de altura fija, el propio botón se convierte en contenedor flex: display: inline-flex; align-items: center; justify-content: center;.

La alternativa Grid: una sola línea

CSS Grid centra un hijo único con una sola declaración:

css
.conteneur {
  display: grid;
  place-items: center; /* align-items + justify-items */
  min-height: 100vh;
}

Grid y Flexbox dan aquí el mismo resultado. Grid es más corto para un solo elemento; Flexbox sigue siendo más natural para alinear una fila de elementos. La elección entre los dos modelos para una maquetación completa está detallada en Grid o Flexbox.

position absolute + transform: el caso de las superposiciones

Cuando el elemento que hay que centrar está fuera del flujo, por ejemplo un tooltip o una ventana modal colocada por encima de la página, se posiciona al 50 % y luego se retrocede la mitad de su propio tamaño:

css
.parent {
  position: relative;
}

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

El método funciona sin conocer el tamaño del elemento, pero puede dejar el texto ligeramente borroso cuando la traslación cae en medio píxel. Para una modal a pantalla completa, un contenedor position: fixed; inset: 0; display: grid; place-items: center; evita el problema.

Por qué «no funciona»: los cinco errores

  1. El padre no tiene altura. El centrado vertical es relativo a la altura del contenedor; sin altura no hay nada que centrar. Añade min-height.
  2. Las propiedades están en el hijo. justify-content y align-items van en el padre. En el hijo solo actúan align-self y margin: auto.
  3. margin: 0 auto sin anchura. El bloque ya ocupa el 100 %: dale una width o una max-width.
  4. text-align: center para centrar un div. Centra el texto de dentro, no la caja. Usa Flexbox o los márgenes automáticos.
  5. height: 100% que no hace nada. Un porcentaje de altura solo vale si el padre tiene a su vez una altura definida, hasta html. 100vh y 100dvh no dependen del padre.

Resumen

Quiero centrar… Método
un div en los dos sentidos padre display: flex; justify-content: center; align-items: center; (+ altura)
un div en horizontal, sin Flexbox width + margin: 0 auto
un solo hijo, con lo mínimo padre display: grid; place-items: center;
en toda la página lo mismo + min-height: 100vh
una imagen text-align: center en el padre, o Flexbox dentro de un marco
un texto o un botón text-align: center en el bloque padre
una superposición (modal, tooltip) position: absolute; top/left: 50%; transform: translate(-50%, -50%)

Para ir más allá del centrado, la guía completa de Flexbox repasa todas las propiedades del contenedor y de los hijos.

Errores frecuentes

El contenedor no tiene altura align-items: center centra respecto a la altura del contenedor. Si es la misma que la del contenido, no se mueve nada. Dale una altura al contenedor (min-height: 100vh, height: 300px).
Poner las propiedades en el hijo justify-content y align-items se aplican al padre en display: flex, no al elemento que se quiere centrar. Solo align-self y margin: auto se aplican al hijo.
margin: 0 auto sin anchura Un bloque sin width ni max-width ya ocupa todo el ancho: los márgenes automáticos valen cero. Fija una anchura.
text-align: center en un div Esta propiedad centra el contenido en línea (texto, imágenes inline) dentro del div, no el div dentro de su padre.

CSS

Damien Flandrin Desarrollador web desde 2010, creador de Gekkode y de Email Impact. Cada artículo se prueba en un proyecto real antes de publicarse. Contacto
Newsletter

Las nuevas pruebas, tutoriales y proyectos, por correo.

Pruebas reproducibles, código versionado, resultados fechados. Nunca spam.