Tema
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):
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
- 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. - Coloca un botón "Cerrar ×" en la esquina superior derecha de un modal.
- Crea un botón flotante "Subir" fijo en la esquina inferior izquierda.
- ¿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;
}- Dos problemas: falta
top: 0y el padre tieneoverflow: hidden, lo que impide el comportamiento sticky. Solución: añadirtop: 0y quitar eloverflow: hiddendel contenedor (o usaroverflow: clip).
Resumen
blockocupa todo el ancho;inlinesólo su contenido e ignora width/height;inline-blockcombina ambos.display: nonequita el elemento;visibility: hiddenlo oculta conservando el espacio.relativedesplaza y sirve de ancla;absolutese posiciona respecto al ancestro posicionado.fixedse fija a la ventana;stickyse pega al hacer scroll dentro de su padre.z-indexsólo funciona en elementos posicionados y dentro de su contexto de apilamiento.- Para centrar:
display: grid; place-items: centeres la forma más corta.
Siguiente: Flexbox a fondo.