- Don’t depend on anything else (screen, parent, user settings).
- Rarely used in modern responsive design (except for print).
| Unit | Meaning | Example Use |
|---|---|---|
px |
Pixels (device pixels / CSS pixels) | Borders, fine UI adjustments |
cm |
Centimeters | Print stylesheets |
mm |
Millimeters | Print stylesheets |
in |
Inches (1in = 96px) | |
pt |
Points (1pt = 1/72in) | Print (fonts in documents) |
pc |
Picas (1pc = 12pt) | Rarely used |
🔑 When to use:
px→ for sharp, precise UI control (icons, borders, shadows).- Physical units (
cm,mm,in,pt) → for print, not screens.
These are the most important for responsive design.
| Unit | Relative To | Example |
|---|---|---|
em |
Parent element’s font-size | 2em = 2 × parent font-size |
rem |
Root (html) font-size |
1rem = consistent across page |
ex |
x-height of font (height of "x") | Rare, typography-specific |
ch |
Width of "0" character | Good for input widths |
🔑 When to use:
em→ for scaling elements based on their parent.rem→ for global consistency (buttons, spacing, typography).ch→ width of inputs based on expected characters (e.g., credit card fields).
| Unit | Relative To | Example |
|---|---|---|
vw |
1% of viewport width | 50vw = 50% of screen width |
vh |
1% of viewport height | 100vh = full screen height |
vmin |
1% of smaller side (width/height) | Keeps square proportions |
vmax |
1% of larger side | Rare, but useful sometimes |
🔑 When to use:
vh,vw→ fullscreen sections, hero images, responsive typography.vmin→ perfect circles/squares responsive to screen.
- Relative to parent element’s size (width, padding, margin).
- Example:
width: 50%→ half the parent’s width.
🔑 When to use:
- Flexible layouts, grids, fluid images.
calc()→ do math with units (width: calc(100% - 50px)).min(),max(),clamp()→ responsive font sizing & layouts.
Example:
font-size: clamp(1rem, 2vw, 2rem);➡️ Min: 1rem, Preferred: scales with screen (2vw), Max: 2rem.
px→ fine control (borders, icons, shadows, pixel-perfect tweaks).rem→ global scaling (font sizes, spacing, layout consistency).em→ local scaling (nested elements, responsive padding).%→ fluid layouts inside parent containers.vw/vh→ full-screen sections, fluid typography, responsive hero banners.ch→ form input widths (based on characters).- Physical units (
cm,pt, etc.) → only for print.
âś… Best practice today:
- Use
remfor typography and spacing → scalable & consistent. - Use
%,vw,vhfor layouts → responsive. - Use
pxsparingly for precise details. - Combine with
clamp()for modern, flexible responsive design.
Every position value, how offsets (top/right/bottom/left) work, the containing block/offset parent, stacking contexts / z-index, useful patterns, gotchas, performance tips, and best practices.
static— default. Not positioned. Offsets ignored.relative— stays in flow; offsets move it visually but reserve its original space. Great as an anchor for absolutely-positioned children.absolute— removed from normal flow; positioned relative to the nearest positioned ancestor (non-static) — or the initial containing block if none. Useful for overlays/tooltips.fixed— removed from flow; positioned relative to the viewport (so it “stays put” while scrolling) unless some ancestor creates a containing block (see transforms/filters). Great for sticky UI like fixed headers.sticky— hybrid: acts likerelativeuntil it crosses a threshold, then becomes fixed within its scroll container (needstop/left/etc to work). Great for sticky headers inside a section.inherit/initial/unset— CSS keywords; not positioning modes themselves.
- Default for all elements.
top/right/bottom/leftandz-indexhave no effect.- Use when we want normal document flow.
-
Element remains in the normal document flow.
-
top/right/bottom/leftshift the visual rendering but don’t change layout space — the browser still reserves the original position. -
Common uses:
- Nudge an element slightly (micro layout tweaks).
- Serve as an anchor (containing block) for absolutely-positioned child elements (
position: absoluteancestors look for the nearest ancestor withpositionâ‰static).
-
Example:
.box { position: relative; top: 8px; left: 4px; }-
Removed from normal flow — it does not affect sibling layout and siblings don’t reserve space for it.
-
Positioned with
top/right/bottom/leftrelative to its containing block:- The containing block is the nearest ancestor whose
positionis notstatic(e.g.,relative,absolute,fixed,sticky) — usually the offset parent. - If no such ancestor exists, the initial containing block (often the viewport) is used.
- The containing block is the nearest ancestor whose
-
Width/height and offset resolution rules can be tricky — if
left&rightare both specified andwidthauto — the browser stretches/shrinks accordingly (used for responsive overlays). -
Use cases: dropdowns, tooltips, full-screen overlays (with
top:0; left:0; right:0; bottom:0). -
Centering example:
.parent { position: relative; }
.child {
position: absolute;
left: 50%; top: 50%;
transform: translate(-50%, -50%); /* true centering */
}- Also removed from flow.
- Positioned relative to the viewport — it stays visible while the page scrolls (ideal for persistent headers/footers, modals, sticky action buttons).
- Important caveat: ancestors with certain CSS (like
transform,filter,perspective,will-change,contain, somepositioncontexts) can create a new containing block, so afixedelement may become fixed relative to that ancestor rather than the viewport in modern browsers. Keep that in mind if a “fixed” element behaves oddly. - Example:
.header {
position: fixed;
top: 0; left: 0; right: 0;
height: 60px;
}-
A hybrid between
relativeandfixed. -
Behavior: acts as
relativeuntil the element would scroll beyond its threshold (e.g.,top: 0), then it becomes fixed within the bounds of its nearest scroll container (it won’t escape its parent container). -
Requirements & gotchas:
- Needs at least one offset (
top,bottom,left, orright) to take effect. - The element’s parent (containing block) defines the boundary — it will not stick past the parent’s edges.
- Sticky behavior depends on the scroll container; if ancestor layout or overflow creates a new scroll context, sticky will act inside that context. Browser inconsistencies historically exist with table elements and some overflow scenarios, so test.
- Needs at least one offset (
-
Example (sticky header within a section):
.section-header {
position: sticky;
top: 0; /* stick to top of scroll container */
z-index: 10;
}-
Offsets control the element’s position relative to its containing block (or its normal position for
relative). -
Values can be lengths,
%(percent is relative to containing block’s dimensions), orauto. -
insetshorthand =top right bottom left. -
For
relativeelements: offsets shift the element but leave layout space unchanged. -
For
absolute/fixed/sticky: offsets move the element and affect layout because the element is not in normal flow (except sticky behaves relative until threshold). -
Interaction rules (short summary):
- If both
leftandrightareautoandwidthisauto, the element may shrink-to-fit. - If
leftandrightdefined andwidth: auto, width adjusts to satisfy offsets (useful for full-width absolute elements).
- If both
- Containing block determines the reference for offsets.
- For
absolute: nearest ancestor withpositionâ‰static(padding box is used). - For
fixed: normally the viewport, but transforms/filters/perspective/contain/will-change on an ancestor can create a containing block that makesfixedbehave like absolute relative to that ancestor. - For
sticky: its containing block is the ancestor that establishes the scrolling container — sticky sticks within that ancestor’s bounds. offsetParent(DOM API) returns the nearest ancestor used for computing offsets — useful in JS, but it follows rules and can differ across browsers in edge cases.
-
z-indexonly applies to positioned elements (positionother thanstatic) or flex/grid items with certain properties. -
Stacking context = an isolated stacking level. Descendants with
z-indexare compared inside their stacking context; they cannot escape it to be stacked against elements in other contexts. -
Common triggers for creating a stacking context:
- The root element (document).
- An element with
positionâ‰staticandz-indexvalue other thanauto. - An element with
opacity< 1. - An element with a
transformnotnone. filter,perspective,mix-blend-mode,isolation:isolate,will-changewith certain values,contain:paint,backdrop-filter, etc.
-
Implications:
- If a parent creates a stacking context (e.g., via
transform), a child’sz-indexwill be relative to that parent’s stacking context — even a very largez-indexon the child won’t escape the parent’s stacking context. - Typical modal/overlay problems happen when the overlay is in a lower stacking context than other elements; the fix is to ensure overlay’s ancestor doesn’t create low-level stacking contexts, or move overlay in the DOM near
<body>.
- If a parent creates a stacking context (e.g., via
-
Any element can be positioned (
positionapplies regardless ofdisplay), but visual behavior differs:position: relativeon an inline element will shift it visually, but it still occupies inline space (line-height/flow preserved).position: absoluteon an inline element makes it out-of-flow and behaves like a block-level positioned box.
-
For layout work, prefer block or flex/grid containers; inline positioning is useful for small tweaks/icons inside text.
.parent { position: relative; }
.modal {
position: absolute;
left: 50%; top: 50%;
transform: translate(-50%, -50%);
}.overlay {
position: fixed;
inset: 0; /* top:0; right:0; bottom:0; left:0 */
background: rgba(0,0,0,0.5);
}thead th { position: sticky; top: 0; background: white; z-index: 2; }.card { position: relative; }
.card .badge { position: absolute; right: 8px; top: 8px; }- Animating
top/lefttriggers layout (reflow) — expensive. Prefertransform: translate()andopacityfor smooth, hardware-accelerated animations (compositor-only). positionchanges themselves are fine, but avoid layout-thrashing loops in JS (read/write DOM alternation).
position: fixedheaders can cover content — remember to add top padding/margin to main content, or usescroll-padding-topwhen using anchor links.- Keyboard focus: ensure modals/overlays trap focus and are accessible (use
aria-hidden, focus management). - Don’t rely on
positionto solve semantic structure — use it for presentation.
-
Modal behind page elements — stacking context issue. Fix: ensure overlay is in a high stacking context (often move modal to document root via portal).
-
position: fixedseems relative to a parent — likely an ancestor hastransform/filter/will-change— remove that or move the fixed element. -
position: stickynot working — check that:- You have
top/leftetc set, - The parent has enough height area for sticking,
- Ancestors aren’t creating odd scroll containers unintentionally.
- You have
-
Absolute child not positioned where expected — ensure parent has
position: relative.
static→ default; normal flow.relative→ micro-adjustment or anchor for absolutely-positioned children.absolute→ UI elements removed from flow (tooltips, dropdowns, icons inside a container).fixed→ persistent elements relative to viewport (global nav, floating action button). Watch transforms on ancestors.sticky→ section headers that should stick within their parent’s bounds while scrolling.
- The CSS spec defines precisely how containing blocks are established; transforms and some other CSS create containing blocks and stacking contexts — that’s often why real-world behavior differs from naive expectations. If we hit quirky behavior, we inspect ancestors for
transform,will-change,filter,positionandz-index. - Mobile browsers historically have quirks with
position: fixed(soft keyboard, viewport behavior). Test on devices.