Saltar al contenido
centrar.css · devschool

Centrar elementos en CSS

Lección 17 de 50 · 13 min de lectura · Actualizado el

En esta lección
  1. Antes de empezar: ¿centrar qué y dónde?
  2. Centrar texto: text-align
  3. Centrar un bloque en horizontal: margin: auto
  4. Centrar con Flexbox (horizontal y vertical)
  5. Centrar con Grid: place-items
  6. Centrar con position
  7. Centrar en vertical dentro de un contenedor con altura
  8. Centrar una imagen
  9. Centrar en toda la pantalla
  10. Qué método usar en cada caso
  11. Errores frecuentes
  12. Resumen

“¿Cómo centro un div?” es probablemente la pregunta más repetida de la historia de CSS. Durante años hubo que recurrir a trucos raros, pero hoy hay formas limpias y fiables. El problema es que no existe una única propiedad “centrar”: el método depende de qué quieres centrar (texto, un bloque, una imagen), en qué dirección (horizontal, vertical o las dos) y de cómo está maquetado el contenedor. En esta lección tienes un recetario con cada caso y, al final, una tabla para elegir el método adecuado sin dudar.

Antes de empezar: ¿centrar qué y dónde?

Para centrar algo siempre hay dos piezas: el contenedor (la caja dentro de la que centras) y el elemento que quieres centrar. Hazte tres preguntas:

  1. ¿Es texto o algo en línea (un enlace, un <span>, una imagen) o es un bloque (un <div>, una tarjeta)? Recuerda la diferencia en bloque y en línea.
  2. ¿Horizontal, vertical o ambos?
  3. ¿El contenedor tiene altura? Centrar en vertical solo tiene sentido si hay espacio sobrante arriba y abajo. Un <div> normal mide lo que mide su contenido, así que, si no le das altura, no hay nada que centrar en vertical.

Esta última es la causa número uno de “no me centra en vertical”: el contenedor es exactamente igual de alto que el contenido.

Centrar texto: text-align

Para centrar texto y elementos en línea dentro de un bloque, usa text-align: center en el contenedor:

.cabecera {
  text-align: center;
}
<header class="cabecera">
  <h1>Gimnasio Montaña</h1>
  <p>Abierto de lunes a sábado</p>
  <a href="/horarios/">Ver horarios</a>
</header>

El título, el párrafo y el enlace quedan centrados. text-align se hereda, así que afecta a todo el texto de dentro.

Cuidado: text-align: center no centra un <div> con anchura propia, solo su contenido en línea. Si pones text-align: center a una tarjeta de 300 px, se centra el texto de la tarjeta, no la tarjeta.

Un truco útil: si conviertes un elemento en inline-block, se comporta como una “palabra” grande y sí se centra con text-align del padre.

.pie { text-align: center; }
.pie .boton { display: inline-block; padding: 8px 16px; }

Centrar un bloque en horizontal: margin: auto

Para centrar un bloque (un <div>, un <main>, un formulario) dentro de su padre, dale un ancho menor que el del padre y márgenes laterales automáticos:

.contenedor {
  max-width: 960px;
  margin-inline: auto;   /* igual que margin-left: auto; margin-right: auto; */
  padding-inline: 16px;
}

El navegador reparte el espacio sobrante a partes iguales entre los dos márgenes, y el bloque queda centrado. Es la forma clásica de centrar el contenido principal de una web.

Las dos condiciones son imprescindibles:

  • El elemento debe ser de bloque (display: block, que es lo normal en un <div>).
  • Debe tener un ancho (width o max-width) menor que el del padre. Si ocupa el 100 %, no queda espacio que repartir.

Verás mucho margin: 0 auto, que hace lo mismo y además pone a cero los márgenes de arriba y abajo. margin-inline: auto es la versión moderna y solo toca los laterales.

Consejo: usa max-width en vez de width. Con width: 960px, en un móvil de 390 px el bloque se saldría de la pantalla; con max-width, se encoge.

¿Y en vertical con margin: auto?

En un bloque normal, margin-top: auto y margin-bottom: auto valen cero, así que no centran en vertical. Sí funcionan dentro de un contenedor Flexbox o Grid, como verás a continuación.

Centrar con Flexbox (horizontal y vertical)

Flexbox es la forma más popular de centrar en las dos direcciones. Se aplica al contenedor:

.portada {
  display: flex;
  justify-content: center;  /* eje principal: horizontal */
  align-items: center;      /* eje cruzado: vertical */
  min-height: 400px;
}

Todo lo que haya dentro de .portada queda centrado. Si hay varios hijos, se colocan en fila y la fila entera queda centrada. Si quieres que se apilen en columna y sigan centrados, añade flex-direction: column (recuerda que entonces los ejes se intercambian, pero con center en los dos el resultado es el mismo).

Otra forma, muy cómoda cuando solo hay un hijo:

.portada { display: flex; min-height: 400px; }
.portada > .tarjeta { margin: auto; }

Dentro de un contenedor flex, margin: auto sí reparte el espacio en las dos direcciones, así que el hijo queda en el centro exacto.

Centrar solo uno de los ejes

Como cada propiedad controla un eje, puedes centrar solo uno:

/* Barra de menú: elementos centrados en vertical, pegados a la izquierda */
.barra {
  display: flex;
  align-items: center;
  gap: 16px;
  height: 64px;
}

Este es el caso más habitual en la vida real: un logo, unos enlaces y un botón en una barra, todos alineados por su centro aunque tengan alturas distintas.

Centrar con Grid: place-items

Con Grid se consigue lo mismo con aún menos código:

.portada {
  display: grid;
  place-items: center;
  min-height: 400px;
}

place-items es un atajo de align-items (vertical) y justify-items (horizontal). Con un solo valor, se aplica a los dos. Son dos líneas que centran cualquier cosa: por eso es la receta favorita de mucha gente.

Diferencia con Flexbox cuando hay varios hijos: Grid los apila uno debajo de otro (cada uno en su fila) y los centra; Flexbox los pone uno al lado del otro. Elige según cómo quieras que se distribuyan.

También existe place-content: center, que centra la rejilla entera dentro del contenedor en vez de cada elemento dentro de su celda. Con un solo hijo, el resultado visual es casi el mismo.

Centrar un solo elemento de la rejilla

Si solo uno de los hijos debe ir centrado en su celda, usa place-self en ese hijo:

.galeria { display: grid; grid-template-columns: repeat(3, 1fr); }
.galeria .destacado { place-self: center; }

Centrar con position

Cuando un elemento está posicionado de forma absoluta (una etiqueta sobre una foto, un botón de reproducir sobre un vídeo), Flexbox y Grid del padre no le afectan del mismo modo. Hay dos recetas. En ambas, el padre debe ser el bloque de referencia, normalmente con position: relative (lo tienes explicado en posicionamiento).

top, left y transform

.video { position: relative; }

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

¿Por qué hace falta el transform? top: 50% y left: 50% colocan la esquina superior izquierda del botón en el centro del padre, así que el botón queda desplazado hacia abajo y a la derecha. translate(-50%, -50%) lo mueve hacia atrás la mitad de su propio ancho y alto, y ahora sí queda centrado. Funciona aunque no sepas cuánto mide el botón. Tienes más sobre translate en transformaciones.

inset: 0 y margin: auto

Si el elemento tiene un tamaño definido, hay una receta sin transform:

.video .play {
  position: absolute;
  inset: 0;          /* top, right, bottom y left a 0 */
  margin: auto;
  width: 64px;
  height: 64px;
}

Al estirar el elemento hacia los cuatro lados con inset: 0 y fijarle un tamaño, el navegador reparte el espacio que sobra en los márgenes automáticos. Es útil si ya usas transform para otra cosa (por ejemplo, una animación de escala), porque dos transform en la misma regla se pisan.

Centrar en vertical dentro de un contenedor con altura

Imagina una tarjeta de 200 px de alto con un texto corto que quieres en el centro. Cualquiera de estas opciones funciona:

/* Opción A: Grid */
.tarjeta { height: 200px; display: grid; place-items: center; }

/* Opción B: Flexbox */
.tarjeta { height: 200px; display: flex; align-items: center; justify-content: center; }

/* Opción C: solo vertical, mantiene el texto alineado a la izquierda */
.tarjeta { height: 200px; display: flex; flex-direction: column; justify-content: center; }

Verás en código antiguo el truco de line-height igual a la altura (height: 50px; line-height: 50px;). Solo funciona con una única línea de texto: si el texto ocupa dos líneas, cada una mide 50 px y se sale de la caja. Hoy no hace falta.

También existe align-content: center en un bloque normal: los navegadores actuales permiten usarlo sin Flexbox ni Grid para centrar en vertical el contenido de un bloque con altura. Es muy reciente, así que de momento quédate con Flexbox o Grid si necesitas compatibilidad con navegadores algo antiguos.

Centrar una imagen

Una <img> es un elemento en línea, así que tienes dos opciones:

/* Opción 1: centrarla como texto desde el padre */
.foto-producto { text-align: center; }

/* Opción 2: convertirla en bloque y usar margin auto */
.foto-producto img {
  display: block;
  margin-inline: auto;
  max-width: 100%;
}

La opción 2 es la más usada porque además elimina el pequeño hueco que deja una imagen en línea debajo de ella (el espacio reservado para las letras con “patita”, como la g o la p).

Si la imagen está dentro de un <figure> con un pie de foto, centra los dos con Grid o Flexbox en columna:

figure {
  display: flex;
  flex-direction: column;
  align-items: center;
}

Y si lo que quieres es centrar lo que se ve de una imagen recortada (por ejemplo, la cara en una foto de perfil cuadrada), eso no se hace moviendo el elemento sino con object-position, que tienes en imágenes en CSS.

Centrar en toda la pantalla

Para una pantalla de bienvenida, un mensaje de “cargando” o una página de inicio de sesión, quieres el contenido en el centro de la ventana. El truco es darle al contenedor la altura de la pantalla:

.pantalla-login {
  min-height: 100dvh;
  display: grid;
  place-items: center;
}

La unidad dvh (dynamic viewport height) es el alto de la ventana teniendo en cuenta la barra de direcciones del móvil, que aparece y desaparece. Con 100vh a veces el contenido queda tapado por esa barra. Lo tienes en unidades.

Usa min-height y no height: si el formulario es más alto que la pantalla (un móvil en horizontal), con height se cortaría.

Una ventana modal sobre todo

Para un aviso que flota sobre la página:

.modal {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  background: rgb(0 0 0 / 0.5);   /* fondo oscuro semitransparente */
}

position: fixed con inset: 0 hace que el fondo cubra la ventana completa, y place-items centra el cuadro de diálogo. Si usas el elemento <dialog> de HTML, el navegador ya lo centra por ti al abrirlo con showModal(); lo tienes en details y dialog.

Qué método usar en cada caso

Quiero centrar…Método recomendadoSe aplica en
Texto, enlaces, iconos en líneatext-align: centerEl contenedor
Un bloque en horizontal (la web, un formulario)max-width + margin-inline: autoEl elemento
Una cosa en horizontal y verticaldisplay: grid; place-items: centerEl contenedor
Varios elementos en fila, centradosdisplay: flex; justify-content: center; align-items: centerEl contenedor
Elementos de una barra alineados por su centrodisplay: flex; align-items: centerEl contenedor
Un elemento absoluto sobre otrotop/left: 50% + translate(-50%, -50%)El elemento
Un elemento absoluto de tamaño fijoinset: 0 + margin: autoEl elemento
Una imagendisplay: block; margin-inline: autoLa imagen
Contenido en el centro de la pantallamin-height: 100dvh + GridEl contenedor
Una modalposition: fixed; inset: 0 + GridEl fondo de la modal

Si dudas, empieza por Grid con place-items: center para una sola cosa y por Flexbox cuando haya varias en fila.

Errores frecuentes

  • El contenedor no tiene altura. Si el padre mide lo mismo que el hijo, centrar en vertical no tiene efecto. Dale min-height o comprueba en DevTools cuánto mide.
  • Poner las propiedades en el sitio equivocado. justify-content, align-items y place-items van en el padre; margin: auto y place-self van en el hijo.
  • Usar margin: auto sin ancho. Un bloque que ocupa el 100 % no puede centrarse porque no sobra espacio. Ponle max-width.
  • Esperar que text-align centre un bloque. Solo centra contenido en línea. Para el bloque, margin-inline: auto.
  • Olvidar el transform en la receta de position. Con solo top: 50%; left: 50%, el elemento queda desplazado hacia abajo y a la derecha.
  • Usar height: 100vh en móviles. La barra del navegador tapa parte del contenido. Mejor min-height: 100dvh.
  • Centrar en vertical con line-height. Se rompe en cuanto el texto ocupa dos líneas.

Resumen

TécnicaQué centraEjemplo
text-align: centerContenido en línea, en horizontal.cabecera { text-align: center; }
margin-inline: autoUn bloque con ancho, en horizontal.web { max-width: 960px; margin-inline: auto; }
FlexboxUno o varios hijos, en uno o dos ejesdisplay: flex; justify-content: center; align-items: center;
GridUno o varios hijos, en los dos ejesdisplay: grid; place-items: center;
position + transformElemento absoluto de tamaño desconocidotop: 50%; left: 50%; transform: translate(-50%, -50%);
inset: 0 + margin: autoElemento absoluto de tamaño fijoposition: absolute; inset: 0; margin: auto;
min-height: 100dvhContenido en la pantalla completamin-height: 100dvh; display: grid; place-items: center;

Muchas de estas recetas usan Flexbox. En la siguiente lección lo aprenderás a fondo: Flexbox.

Pruébalo tú

Cambia el código y pulsa Ejecutar (o Ctrl + Enter).

centrar.html
Resultado

Pon a prueba lo que has aprendido

[CSS] ¿Cuál es la forma más corta de centrar un elemento en horizontal y vertical dentro de su contenedor con Grid?

[CSS] Tienes <div class="tarjeta"> de 300 px de ancho y le pones text-align: center. ¿Qué se centra?

[CSS] Con position: absolute, pones top: 50%; left: 50% y el elemento queda descentrado hacia abajo y a la derecha. ¿Qué falta?

[CSS] ¿Por qué es mejor min-height: 100dvh que height: 100vh para ocupar toda la pantalla?

¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.