De CSS-eigenschap position is het kerngereedschap dat bepaalt hoe een element op de pagina wordt geplaatst en of offsets als top, right, bottom, left (en inset) er überhaupt op van toepassing zijn. De meeste verwarring komt doordat men niet precies weet hoe de vijf waarden (static, relative, absolute, fixed, sticky) van elkaar verschillen. In dit artikel verhelder ik ze stuk voor stuk met echte voorbeelden en werkende code.
position: static — het standaardgedrag
Elk element komt standaard met position: static tenzij je iets anders opgeeft. Statische elementen staan in de normale flow: blokelementen stapelen verticaal, inline-elementen lopen naast elkaar. Het belangrijkste detail: offset-eigenschappen als top en left hebben geen effect op een statisch element. z-index evenmin.
.vak {
position: static; /* standaard */
top: 50px; /* geen enkel effect */
}
Wil je een element verschuiven, dan is de eerste stap het uit de statische staat halen.
position: relative — verschuiven ten opzichte van zichzelf
relative houdt het element in de normale flow maar laat je offsets toepassen. Die offsets worden berekend ten opzichte van de oorspronkelijke positie van het element. Belangrijk: ook als het element verschuift, blijft zijn oorspronkelijke plek in de flow behouden — naburige elementen gedragen zich alsof het er nog staat, en er blijft geen gat achter.
.badge {
position: relative;
top: -8px;
left: 12px;
}
Het tweede, even gangbare gebruik van relative is onzichtbaar: het creëert een positioneringscontext voor de absolute elementen erbinnen. Vaak geef je een vak position: relative zonder enige offset; je enige doel is de kinderen eraan te verankeren.
position: absolute — uit de flow
absolute haalt het element volledig uit de normale flow; het neemt geen ruimte meer in voor zijn buren. De positie wordt berekend vanaf de dichtstbijzijnde gepositioneerde voorouder (de dichtstbijzijnde ouder waarvan position niet static is). Bestaat zo'n voorouder niet, dan valt de referentie terug op het initiële containerblok (meestal de viewport / <html>).
Het klassieke patroon is: relative aan de buitenkant, absolute aan de binnenkant.
.kaart {
position: relative;
}
.kaart .label {
position: absolute;
top: 8px;
right: 8px;
}
Hier plakt .label in de rechterbovenhoek van de kaart. Zonder relative op .kaart zou het label wegvliegen naar de dichtstbijzijnde gepositioneerde voorouder op de pagina. Daarom is het antwoord op "mijn absolute element staat op de verkeerde plek" bijna altijd: je bent vergeten relative op de juiste voorouder te zetten.
- Stel je zowel
topalsbottomin zonder hoogte, dan rekt het element verticaal uit. - De afkorting
inset: 0zet alle vier de randen op 0 en rekt het element uit om zijn voorouder volledig te bedekken.
position: fixed — vastgezet aan de viewport
fixed haalt het element ook uit de flow, maar de referentie is altijd de viewport (geen voorouder). Het element blijft op zijn plek op het scherm, zelfs als de pagina scrollt. Ideaal voor vaste navigatiebalken, "naar boven"-knoppen en cookiebanners.
.feedback {
position: fixed;
right: 20px;
bottom: 20px;
z-index: 1000;
}
Eén cruciale uitzondering: heeft een voorouder een eigenschap als transform, filter of perspective, dan maakt die voorouder een nieuw containerblok, en wordt het fixed element vastgezet ten opzichte van die voorouder in plaats van de viewport. Drijft een fixed element onverwacht weg, controleer dan of een ouder een transform heeft.
position: sticky — tussen relative en fixed in
sticky is een hybride van de twee. Het element staat eerst in de normale flow als relative; terwijl je scrollt en het de drempel bereikt die je hebt ingesteld (bijv. top: 0), plakt het vast als fixed. Bij het einde van zijn container wordt het weer losgelaten.
.sectiekop {
position: sticky;
top: 0;
background: #fff;
}
Werkt sticky niet, dan zijn er drie gebruikelijke oorzaken:
- Ontbrekende drempel: je moet minstens één van
top,bottom,leftofrightopgeven; zonder die plakt er niets. overflowop een voorouder: heeft een ouderoverflow: hidden/scroll/auto, dan bindt het sticky-element zich aan de scrollcontext van die container en gedraagt het zich niet zoals verwacht.- Te weinig ruimte: een sticky-element blijft alleen plakken over de lengte van zijn eigen container; is die kort, dan duurt het effect maar kort.
z-index en stacking contexts
z-index werkt alleen op gepositioneerde elementen (elke waarde behalve static) en op flex/grid-kinderen. Een hogere z-index brengt een element naar voren — maar alleen binnen dezelfde stacking context. Eigenschappen als transform, opacity (onder 1) en filter maken een nieuwe stacking context aan; daarom kan soms zelfs z-index: 9999 een element niet naar boven tillen: het zit gevangen in een context met lagere prioriteit.
Welke waarde, en wanneer?
- Alleen een kleine verschuiving terwijl de flow behouden blijft? →
relative - Een element in de hoek van een ander plaatsen? →
relativeop de ouder,absoluteop het kind - Moet het vast op het scherm blijven ongeacht het scrollen? →
fixed - Moet het bij het scrollen plakken maar aan het einde van de sectie loslaten? →
sticky
Veelgestelde vragen
Wat is het verschil tussen absolute en fixed?
Beide halen het element uit de normale flow. absolute wordt gepositioneerd ten opzichte van de dichtstbijzijnde gepositioneerde voorouder en scrollt mee met de pagina; fixed wordt gepositioneerd ten opzichte van de viewport en blijft op zijn plek op het scherm, ook bij het scrollen.
Waarom plakt mijn sticky-element helemaal niet?
De twee meest voorkomende redenen: je hebt geen drempelwaarde opgegeven (zoals top/bottom), of een ouder heeft overflow: hidden of overflow: auto. Dat laatste schakelt sticky stilletjes uit.
Waarom werkt mijn z-index niet?
Meestal omdat het element static is (geef het eerst een positiewaarde) of omdat het vastzit in een stacking context met lagere prioriteit. Controleer de voorouders op transform, opacity of filter.
Breekt je interface door positionering? We kunnen sticky headers, dropdown-overlap en laagproblemen samen op orde brengen. Heb je een project, neem dan contact met me op.