Position
Lección 10 de 37 · 4 min
position decide si una caja sigue el flujo normal o se ubica por su cuenta. Todo se reduce a una pregunta: contra qué se mide cada caja.
Static, relative y absolute
position tiene cinco valores. Los primeros tres:
- Estático
staticEl valor por defecto. La caja sigue el flujo ytop,right,bottomyleftno tienen efecto. - Relativa
relativeLa caja se corre desde su propio lugar, pero ese lugar queda reservado. Las vecinas no se mueven. - Absoluta
absoluteLa caja sale del flujo, las vecinas ocupan su lugar y los desplazamientos se miden contra su bloque contenedor (containing block).
El bloque contenedor de una caja absoluta es el ancestro posicionado más cercano: el primero con un position distinto de static (un transform también cuenta). Se mide desde el borde interno de ese ancestro, donde empieza el relleno. Si no hay ninguno, la caja se mide contra el bloque contenedor inicial: un rectángulo del tamaño de la ventana, al principio de la página.
Elegí un valor, mové top y left y destildá el ticket para ver contra qué se mide el sello. El contorno naranja marca la caja desde la que se miden top y left, y el punteado gris, el lugar del sello en el flujo.
Del Molino
14/10 · 09:12
- Medialunas ×6$ 4.800
- Pan de campo$ 3.200
- Café en grano 250 g$ 7.900
Total$ 15.900
.ticket {position: relative;}.sello {position: absolute;top: 16px;left: 16px;}
<div class="relative">…<div class="absolute top-4 left-4">Pagado</div>…</div>
Fixed y sticky
fixed funciona como absolute, pero se mide contra la ventana: la caja queda quieta cuando la página scrollea. Por eso no está en la demo, se iría de ella. Ojo: si un ancestro tiene transform, filter o perspective, la caja se mide contra ese ancestro y deja de quedar fija en la ventana.
sticky es un híbrido: la caja ocupa su lugar como relative hasta que el scroll la lleva al umbral que le diste, y ahí se pega. Para que funcione:
- Un umbral
top: 0Necesita un desplazamiento, comotop: 0. Sin ninguno, nunca se pega. - Su contenedor de scroll
overflowSe pega dentro de su contenedor de scroll más cercano. Un ancestro conoverflow: hiddentambién es uno, aunque no scrollee, así que la caja deja de pegarse al scroll de la página. Si solo necesitás recortar,overflow: clipno crea uno. - Su padre
límiteNo sale de su padre: cuando el padre termina, se va con él.
inset es el atajo de top, right, bottom y left, en el mismo orden que padding:
.capa {position: absolute;inset: 0; /* los cuatro en 0: cubre el bloque contenedor */}.encabezado {position: sticky;top: 0;}
Capas y z-index
Cuando dos cajas se superponen, las posicionadas se pintan encima de las que no lo están, y entre ellas gana la que viene después en el HTML. z-index cambia ese orden: el número más alto queda adelante. Solo funciona en cajas posicionadas (cualquier valor menos static) y en hijos de flex o grid.
Los números no compiten en toda la página, sino dentro de un contexto de apilamiento (stacking context). Cada contexto se pinta como un bloque: nada de adentro puede quedar encima de lo que tapa al contexto entero, aunque tenga z-index: 9999.
Crean un contexto, entre otros:
- Con z-index
position + z-indexUna caja posicionada conz-indexdistinto deauto(fixed y sticky crean uno siempre). - Efectos
opacity · transformopacitymenor a 1 y untransformdistinto denone. - A propósito
isolation: isolateExiste solo para eso: crear un contexto sin cambiar nada más.
.tarjeta {position: relative;isolation: isolate; /* contexto propio */}.tarjeta .fondo {position: absolute;inset: 0;z-index: -1; /* detrás del contenido, pero dentro de la tarjeta */}
En Tailwind
En Tailwind cada valor de position es una clase con el mismo nombre. Los desplazamientos usan la escala de espaciado, que avanza de a 4px (--spacing vale 0.25rem): top-4 son 16px y left-6 son 24px.
| CSS | Tailwind |
|---|---|
| position: relative | relative (y static, absolute…) |
| top: 16px · left: 24px | top-4 · left-6 |
| top: -8px | -top-2 |
| inset: 0 · inset-inline: 0 | inset-0 · inset-x-0 |
| z-index: 10 | z-10 |
| isolation: isolate | isolate |
| height: 160px · overflow-y: auto | h-40 overflow-y-auto |
<!-- insignia en la esquina de la tarjeta --><div class="relative"><img src="foto.jpg" alt="…" /><span class="absolute top-2 right-2 z-10">Nuevo</span></div><!-- encabezado que se pega al hacer scroll --><header class="sticky top-0 z-10">…</header>
Position
Lesson 10 of 37 · 4 min
position decides whether a box follows the normal flow or places itself. It all comes down to one question: what each box is measured against.
Static, relative and absolute
position has five values. The first three:
- Static
staticThe default. The box follows the flow, andtop,right,bottomandlefthave no effect. - Relative
relativeThe box moves from its own spot, but that spot stays reserved. Its neighbors don't move. - Absolute
absoluteThe box leaves the flow, its neighbors take its place, and the offsets are measured against its containing block.
An absolute box's containing block is its nearest positioned ancestor: the first one with a position other than static (a transform counts too). It's measured from that ancestor's inner edge, where the padding starts. If there is none, the box is measured against the initial containing block: a viewport-sized rectangle at the start of the page.
Pick a value, move top and left, and uncheck the receipt to see what the stamp is measured against. The orange outline marks the box top and left are measured from, and the gray dashed one the stamp's spot in the flow.
Mill Street
Oct 14 · 9:12
- Croissants ×6$9.00
- Sourdough loaf$6.50
- Coffee beans 250 g$12.00
Total$27.50
.receipt {position: relative;}.stamp {position: absolute;top: 16px;left: 16px;}
<div class="relative">…<div class="absolute top-4 left-4">Paid</div>…</div>
Fixed and sticky
fixed works like absolute, but it's measured against the viewport: the box stays put when the page scrolls. That's why it isn't in the demo, it would leave it. Watch out: if an ancestor has a transform, filter or perspective, the box is measured against that ancestor and stops being fixed to the viewport.
sticky is a hybrid: the box keeps its spot like relative until scrolling brings it to the threshold you gave it, and then it sticks. For it to work:
- A threshold
top: 0It needs an offset, liketop: 0. With none, it never sticks. - Its scroll container
overflowIt sticks inside its nearest scroll container. An ancestor withoverflow: hiddenis one too, even if it never scrolls, so the box stops sticking to the page's scroll. If you only need to clip,overflow: clipdoesn't create one. - Its parent
limitIt doesn't leave its parent: when the parent ends, it goes with it.
inset is the shorthand for top, right, bottom and left, in the same order as padding:
.overlay {position: absolute;inset: 0; /* all four at 0: covers the containing block */}.header {position: sticky;top: 0;}
Layers and z-index
When two boxes overlap, positioned ones paint over those that aren't, and among them the one that comes later in the HTML wins. z-index changes that order: the higher number goes in front. It only works on positioned boxes (any value but static) and on flex or grid children.
The numbers don't compete across the whole page, but inside a stacking context. Each context paints as one block: nothing inside it can end up above what covers the whole context, even with z-index: 9999.
These create a context, among others:
- With z-index
position + z-indexA positioned box with az-indexother thanauto(fixed and sticky always create one). - Effects
opacity · transformopacitybelow 1 and atransformother thannone. - On purpose
isolation: isolateIt exists only for that: creating a context without changing anything else.
.card {position: relative;isolation: isolate; /* its own context */}.card .backdrop {position: absolute;inset: 0;z-index: -1; /* behind the content, but inside the card */}
In Tailwind
In Tailwind each position value is a class with the same name. The offsets use the spacing scale, which moves in 4px steps (--spacing is 0.25rem): top-4 is 16px and left-6 is 24px.
| CSS | Tailwind |
|---|---|
| position: relative | relative (and static, absolute…) |
| top: 16px · left: 24px | top-4 · left-6 |
| top: -8px | -top-2 |
| inset: 0 · inset-inline: 0 | inset-0 · inset-x-0 |
| z-index: 10 | z-10 |
| isolation: isolate | isolate |
| height: 160px · overflow-y: auto | h-40 overflow-y-auto |
<!-- a badge in the card's corner --><div class="relative"><img src="photo.jpg" alt="…" /><span class="absolute top-2 right-2 z-10">New</span></div><!-- a header that sticks while scrolling --><header class="sticky top-0 z-10">…</header>