CSS Anchor Positioning
Position elements relative to other elements anywhere in the DOM using the CSS Anchor Positioning API, replacing complex JavaScript calculations.
Overview
Key Points
- •anchor-name: --name sets the anchor identifier on the reference element
- •position-anchor: --name connects the positioned element to its anchor
- •anchor() function returns a coordinate from the anchor element
- •The positioned element can be anywhere in the DOM, not just inside the anchor
- •position-try-fallbacks enables automatic repositioning when the preferred position overflows
- •anchor-size() returns the width or height of the anchor element
- •Works with top-layer elements (popover, dialog) that need visual attachment
- •Supported in Chrome 125+ (behind flag in earlier versions)
Examples
Basic tooltip attached to a button
/* The button is the anchor */
.tooltip-trigger {
anchor-name: --tooltip-anchor;
position: relative; /* for inert fallback */
}
/* The tooltip is positioned relative to the anchor */
.tooltip {
position: absolute;
position-anchor: --tooltip-anchor;
bottom: calc(anchor(top) + 8px); /* 8px above the anchor's top edge */
left: anchor(center);
transform: translateX(-50%);
background: #1e293b;
color: white;
padding: 6px 12px;
border-radius: 6px;
font-size: 0.8rem;
white-space: nowrap;
pointer-events: none;
}The tooltip can now be inside a <body> direct child for z-index stacking while still being visually attached to the button.
Dropdown menu with position-try flipping
.menu-btn {
anchor-name: --menu-anchor;
}
.dropdown {
position: fixed; /* in top-layer context */
position-anchor: --menu-anchor;
top: anchor(bottom);
left: anchor(left);
width: anchor-size(width); /* match anchor width */
background: white;
border: 1px solid #e5e7eb;
border-radius: 8px;
box-shadow: 0 8px 24px rgba(0,0,0,0.12);
padding: 4px;
/* Flip above if not enough space below */
position-try-fallbacks: flip-block;
}Connecting a label to a form input
/* Input is the anchor */
.field-input {
anchor-name: --field;
}
/* Error message floats below the input */
.field-error {
position: absolute;
position-anchor: --field;
top: calc(anchor(bottom) + 4px);
left: anchor(left);
color: #ef4444;
font-size: 0.75rem;
font-weight: 500;
background: #fef2f2;
padding: 4px 8px;
border-radius: 4px;
border: 1px solid #fca5a5;
}Sizing with anchor-size()
.popover-trigger {
anchor-name: --pop-anchor;
width: 200px;
}
.popover-content {
position: absolute;
position-anchor: --pop-anchor;
top: anchor(bottom);
left: anchor(left);
/* Match the trigger width */
width: anchor-size(width);
/* Or use a multiplier */
min-width: calc(anchor-size(width) * 1.5);
background: white;
border: 1px solid #e2e8f0;
border-radius: 8px;
padding: 12px;
}anchor-size(width) and anchor-size(height) return the computed width and height of the anchor element.
Common Mistakes
- Using anchor-name without the -- prefix (it must be a custom identifier starting with --)
- Expecting anchor positioning to work without position: absolute or position: fixed on the positioned element
- Forgetting that position-try-fallbacks requires specific keyword values like flip-block and flip-inline
- Assuming wide browser support (Anchor Positioning is Chrome 125+ only as of mid-2024)
Note
Anchor Positioning is the CSS replacement for JavaScript libraries like Floating UI and Popper.js. For tooltips, dropdowns, and context menus that need top-layer stacking but visual attachment, this is the native CSS solution.
Exercises
Write CSS to style the HTML scaffold. The preview updates live — when it looks right, mark as done.
Completed: 0 / 2 exercises
Knowledge Check
Question 1 of 3