Skip to content

Display y posicionamiento ​

¿Por qué un span ignora tu width? ¿Cómo pongo una insignia en la esquina de una tarjeta? ¿Cómo hago un header que se quede fijo arriba? Las respuestas están en dos propiedades: display, que define cómo se comporta una caja en el flujo, y position, que permite sacarla de él. También verás z-index y cómo centrar cualquier cosa.

Concepto: el flujo normal ​

Sin CSS, los elementos se colocan en el flujo normal del documento, como palabras en un libro: los bloques se apilan uno debajo de otro y los elementos en línea se colocan uno junto a otro, como palabras en un renglón.

Analogía

Los bloques son como párrafos (cada uno empieza en un nuevo renglón y ocupa todo el ancho). Los elementos en línea son como palabras dentro del párrafo.

display ​

block ​

Ocupa todo el ancho disponible y empieza en una línea nueva. Acepta width, height, margin y padding en todas direcciones.

Por defecto son bloque: div, p, h1–h6, ul, li, section, header, footer, form...

inline ​

Ocupa sólo el ancho de su contenido y se coloca en la misma línea. Ignora width y height, y los márgenes/padding verticales no empujan a otros elementos.

Por defecto son inline: span, a, strong, em, img (un caso especial), label...

inline-block ​

Lo mejor de ambos: va en línea, pero respeta width, height y todos los márgenes y paddings.

css
.boton {
  display: inline-block;   /* el <a> ahora acepta padding vertical y width */
  padding: 12px 24px;
  min-width: 160px;
  text-align: center;
}

none ​

Elimina el elemento visualmente y del flujo (como si no existiera). Diferencia con visibility: hidden, que lo oculta pero conserva su espacio:

css
.oculto    { display: none; }        /* no ocupa espacio */
.invisible { visibility: hidden; }   /* ocupa su espacio, pero no se ve */

Ocultar sólo visualmente (para lectores de pantalla)

Para textos que deben leer los lectores de pantalla pero no verse (por ejemplo, "Abrir menú" en un botón con ícono):

css
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

flex y grid ​

Convierten al elemento en un contenedor de layout moderno. Son tan importantes que tienen su propia lección: Flexbox y Grid. Spoiler: hoy se usan para casi todo el maquetado.

position ​

Pruébalo en vivo antes de leer el detalle (haz scroll dentro del recuadro con sticky y fixed):

Valores de position

static (por defecto) ​

El elemento sigue el flujo normal. top, left, z-index no tienen efecto.

relative ​

El elemento se queda en su lugar del flujo (su espacio se conserva), pero puedes desplazarlo visualmente con top, right, bottom, left. Su uso más importante: servir de referencia a hijos con position: absolute.

css
.tarjeta { position: relative; }

absolute ​

El elemento sale del flujo (los demás actúan como si no existiera) y se coloca respecto a su ancestro posicionado más cercano (cualquiera con position distinto de static). Si no hay ninguno, respecto al documento.

html
<article class="producto">
  <span class="producto__insignia">-20 %</span>
  <img src="img/taza.webp" alt="Taza de cerámica artesanal">
  <h3>Taza artesanal</h3>
</article>
css
.producto {
  position: relative;          /* el "ancla" de la insignia */
}

.producto__insignia {
  position: absolute;
  top: 12px;
  right: 12px;                 /* esquina superior derecha de la tarjeta */
  padding: 4px 10px;
  border-radius: 999px;
  background: #dc2626;
  color: #fff;
  font-size: 0.8rem;
  font-weight: 700;
}

Para que un elemento absoluto cubra todo su padre (una capa oscura sobre una imagen, por ejemplo):

css
.overlay {
  position: absolute;
  inset: 0;                    /* = top: 0; right: 0; bottom: 0; left: 0; */
  background: rgb(0 0 0 / 0.5);
}

Error común

Poner position: absolute al hijo y olvidar position: relative en el padre. El hijo se va a la esquina de la página en lugar de la tarjeta.

fixed ​

Sale del flujo y se coloca respecto a la ventana (viewport): no se mueve al hacer scroll. Ideal para botones flotantes de WhatsApp, banners de cookies o barras inferiores en móvil.

css
.whatsapp {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 100;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: #25d366;
}

sticky ​

Un híbrido: se comporta como relative hasta que, al hacer scroll, llega a la posición indicada; entonces se "pega" como fixed, pero sólo dentro de su contenedor padre.

css
.header {
  position: sticky;
  top: 0;                      /* se pega al llegar al borde superior */
  z-index: 50;
  background: #fff;            /* ¡necesita fondo o se verá el contenido detrás! */
}

Sticky que no se pega

Las causas más comunes: no indicaste top, el padre tiene overflow: hidden o auto, o el padre mide lo mismo que el elemento (no tiene recorrido para pegarse).

z-index y contextos de apilamiento ​

Cuando los elementos se superponen, z-index decide cuál queda encima (número mayor = más arriba). Sólo funciona en elementos posicionados (relative, absolute, fixed, sticky) o hijos de flex/grid.

css
.header   { position: sticky; z-index: 100; }
.modal    { position: fixed;  z-index: 1000; }
.tooltip  { position: absolute; z-index: 10; }

Contexto de apilamiento: un elemento con position + z-index, o con opacity menor que 1, transform, filter, etc., crea un "grupo" propio. Sus hijos sólo compiten dentro de ese grupo.

txt
.padre-A (z-index: 1)          .padre-B (z-index: 2)
   └─ .hijo (z-index: 9999)       └─ .hijo (z-index: 1)

El hijo de A nunca quedará encima de B, aunque tenga 9999: su padre está por debajo.

Buena práctica

Define una escala de z-index en variables en lugar de números al azar:

css
:root {
  --z-dropdown: 10;
  --z-sticky: 100;
  --z-overlay: 900;
  --z-modal: 1000;
  --z-toast: 1100;
}

float (histórico) ​

Antes de Flexbox, los layouts se hacían con float. Hoy su único uso razonable es hacer que el texto rodee una imagen:

css
.articulo img.izquierda {
  float: left;
  width: 40%;
  margin: 0 1.5rem 1rem 0;
}

.articulo::after {   /* "clearfix": el contenedor envuelve al elemento flotado */
  content: "";
  display: block;
  clear: both;
}

Si ves float para hacer columnas en código antiguo, es candidato a reescribirse con Flexbox o Grid.

Cómo centrar (cualquier cosa) ​

css
/* 1. Texto o elementos inline dentro de un bloque */
.centrado-texto { text-align: center; }

/* 2. Un bloque con ancho definido, horizontalmente */
.contenedor { max-width: 800px; margin-inline: auto; }

/* 3. Horizontal y vertical con Grid (lo más corto) */
.padre-grid {
  display: grid;
  place-items: center;
  min-height: 100vh;
}

/* 4. Horizontal y vertical con Flexbox */
.padre-flex {
  display: flex;
  justify-content: center;
  align-items: center;
}

/* 5. Con position absolute (p. ej. un ícono de "play" sobre un video) */
.play {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

Ejemplo completo: hero con overlay y header sticky ​

html
<header class="header">Café Aroma</header>

<section class="hero">
  <img src="img/hero.webp" alt="" class="hero__fondo">
  <div class="hero__overlay"></div>
  <div class="hero__contenido">
    <h1>Café de especialidad</h1>
    <a href="#menu" class="boton">Ver menú</a>
  </div>
</section>
css
.header {
  position: sticky;
  top: 0;
  z-index: 100;
  padding: 1rem;
  background: #fff;
  box-shadow: 0 1px 0 #e5e7eb;
}

.hero {
  position: relative;             /* referencia para las capas absolutas */
  min-height: 70vh;
  display: grid;
  place-items: center;            /* centra el contenido */
  overflow: hidden;
  color: #fff;
  text-align: center;
}

.hero__fondo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.hero__overlay {
  position: absolute;
  inset: 0;
  background: rgb(30 15 5 / 0.55); /* oscurece la foto para que el texto sea legible */
}

.hero__contenido {
  position: relative;             /* se apila por encima de las capas anteriores */
  padding: 1rem;
}

Ejercicios ​

  1. Haz que los enlaces de un menú (a) acepten padding vertical y un ancho mínimo de 120px sin dejar de estar en línea.
  2. Coloca un botón "Cerrar ×" en la esquina superior derecha de un modal.
  3. Crea un botón flotante "Subir" fijo en la esquina inferior izquierda.
  4. ¿Por qué este header no se pega al hacer scroll?
css
.contenedor { overflow: hidden; }
.contenedor .header { position: sticky; }
Ver solución
css
/* 1 */
.menu a {
  display: inline-block;
  padding: 10px 16px;
  min-width: 120px;
}

/* 2 */
.modal { position: relative; }
.modal__cerrar {
  position: absolute;
  top: 12px;
  right: 12px;
}

/* 3 */
.subir {
  position: fixed;
  left: 20px;
  bottom: 20px;
  z-index: 100;
}
  1. Dos problemas: falta top: 0 y el padre tiene overflow: hidden, lo que impide el comportamiento sticky. Solución: añadir top: 0 y quitar el overflow: hidden del contenedor (o usar overflow: clip).

Resumen ​

  • block ocupa todo el ancho; inline sólo su contenido e ignora width/height; inline-block combina ambos.
  • display: none quita el elemento; visibility: hidden lo oculta conservando el espacio.
  • relative desplaza y sirve de ancla; absolute se posiciona respecto al ancestro posicionado.
  • fixed se fija a la ventana; sticky se pega al hacer scroll dentro de su padre.
  • z-index sólo funciona en elementos posicionados y dentro de su contexto de apilamiento.
  • Para centrar: display: grid; place-items: center es la forma más corta.

Siguiente: Flexbox a fondo.

Academia Web — aprende, copia y construye.