- 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
rem
for typography and spacing → scalable & consistent. - Use
%
,vw
,vh
for layouts → responsive. - Use
px
sparingly 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 likerelative
until 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/left
andz-index
have no effect.- Use when we want normal document flow.
-
Element remains in the normal document flow.
-
top/right/bottom/left
shift 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: absolute
ancestors 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/left
relative to its containing block:- The containing block is the nearest ancestor whose
position
is 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
&right
are both specified andwidth
auto — 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
, someposition
contexts) can create a new containing block, so afixed
element 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
relative
andfixed
. -
Behavior: acts as
relative
until 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
. -
inset
shorthand =top right bottom left
. -
For
relative
elements: 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
left
andright
areauto
andwidth
isauto
, the element may shrink-to-fit. - If
left
andright
defined 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 makesfixed
behave 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-index
only applies to positioned elements (position
other thanstatic
) or flex/grid items with certain properties. -
Stacking context = an isolated stacking level. Descendants with
z-index
are 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
â‰static
andz-index
value other thanauto
. - An element with
opacity
< 1. - An element with a
transform
notnone
. filter
,perspective
,mix-blend-mode
,isolation:isolate
,will-change
with certain values,contain:paint
,backdrop-filter
, etc.
-
Implications:
- If a parent creates a stacking context (e.g., via
transform
), a child’sz-index
will be relative to that parent’s stacking context — even a very largez-index
on 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 (
position
applies regardless ofdisplay
), but visual behavior differs:position: relative
on an inline element will shift it visually, but it still occupies inline space (line-height/flow preserved).position: absolute
on 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/left
triggers layout (reflow) — expensive. Prefertransform: translate()
andopacity
for smooth, hardware-accelerated animations (compositor-only). position
changes themselves are fine, but avoid layout-thrashing loops in JS (read/write DOM alternation).
position: fixed
headers can cover content — remember to add top padding/margin to main content, or usescroll-padding-top
when using anchor links.- Keyboard focus: ensure modals/overlays trap focus and are accessible (use
aria-hidden
, focus management). - Don’t rely on
position
to 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: fixed
seems relative to a parent — likely an ancestor hastransform
/filter
/will-change
— remove that or move the fixed element. -
position: sticky
not working — check that:- You have
top
/left
etc 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
,position
andz-index
. - Mobile browsers historically have quirks with
position: fixed
(soft keyboard, viewport behavior). Test on devices.