CSS Anchor Positioning Guide
Position tooltips, popovers, and dropdowns relative to anchor elements
using pure CSS - no JavaScript positioning libraries needed.
Experimental Feature
CSS Anchor Positioning is an experimental feature currently supported in Chromium-based browsers (Chrome 125+, Edge 125+). Safari and Firefox do not yet support this feature. Always provide fallback positioning for production use.
Table of Contents
1. Introduction to CSS Anchor Positioning
CSS Anchor Positioning is a new CSS feature that allows you to position elements relative to other "anchor" elements on the page. This is incredibly useful for creating tooltips, popovers, dropdown menus, and other UI components that need to be positioned relative to a trigger element.
Common Use Cases
- Tooltips - Display helpful text near a button or link
- Popovers - Show additional content or forms
- Dropdown menus - Position menus below navigation items
- Context menus - Right-click menus positioned at cursor
- Floating labels - Labels that follow form inputs
- Tour guides - Highlight and explain UI elements
Browser Support
Note: Since this is an experimental feature, you should always provide fallback positioning using JavaScript libraries like Floating UI or Popper.js for production applications that need cross-browser support.
Before Anchor Positioning
Previously, positioning tooltips and popovers required JavaScript to calculate positions, handle viewport boundaries, and update positions on scroll. Now, CSS can handle all of this natively.
Old Approach (JavaScript)
- Calculate element positions manually
- Handle scroll and resize events
- Manage viewport boundary detection
- Use libraries like Popper.js or Floating UI
New Approach (CSS)
- Declare anchor with
anchor-name - Position with
anchor()function - Browser handles viewport automatically
- No JavaScript needed for positioning
2. Creating an Anchor
To use anchor positioning, you first need to designate an element as an anchor using theanchor-name property.
The anchor-name Property
/* Define an element as an anchor */
.trigger-button {
anchor-name: --my-anchor;
}
/* The name must start with two dashes (--) like CSS custom properties */Naming Conventions
- Anchor names must start with
--(two dashes) - Use descriptive names:
--tooltip-trigger,--dropdown-btn - Each anchor name should be unique on the page
- Names follow the same rules as CSS custom properties
Basic Anchor Example
<!-- HTML -->
<button class="trigger-button">Hover me</button>
<div class="tooltip">I'm a tooltip!</div>/* CSS */
.trigger-button {
anchor-name: --tooltip-anchor;
}
.tooltip {
/* We'll position this relative to the anchor */
position: fixed;
position-anchor: --tooltip-anchor;
}Important: The anchored element (tooltip, popover, etc.) should useposition: fixed orposition: absolute for anchor positioning to work correctly.
3. Positioning with Anchors
Once you have an anchor, you can position other elements relative to it using theposition-anchor property and theanchor() function.
The position-anchor Property
/* Connect an element to an anchor */
.tooltip {
position: fixed;
position-anchor: --tooltip-anchor;
}The anchor() Function
The anchor() function returns the position of the anchor element's edge. Use it in inset properties (top, right, bottom, left) to position your element.
/* Position tooltip below the anchor */
.tooltip {
position: fixed;
position-anchor: --tooltip-anchor;
/* Position the tooltip's top edge at the anchor's bottom edge */
top: anchor(bottom);
/* Center horizontally with the anchor */
left: anchor(center);
translate: -50% 0;
}Position Above the Anchor
/* Position tooltip above the anchor */
.tooltip {
position: fixed;
position-anchor: --tooltip-anchor;
/* Position the tooltip's bottom edge at the anchor's top edge */
bottom: anchor(top);
left: anchor(center);
translate: -50% 0;
}Position to the Right
/* Position tooltip to the right of the anchor */
.tooltip {
position: fixed;
position-anchor: --tooltip-anchor;
/* Position the tooltip's left edge at the anchor's right edge */
left: anchor(right);
top: anchor(center);
translate: 0 -50%;
}Position to the Left
/* Position tooltip to the left of the anchor */
.tooltip {
position: fixed;
position-anchor: --tooltip-anchor;
/* Position the tooltip's right edge at the anchor's left edge */
right: anchor(left);
top: anchor(center);
translate: 0 -50%;
}Adding Offset/Gap
/* Add spacing between anchor and tooltip */
.tooltip {
position: fixed;
position-anchor: --tooltip-anchor;
/* Use calc() to add offset */
top: calc(anchor(bottom) + 8px);
left: anchor(center);
translate: -50% 0;
}
/* Or use margin */
.tooltip {
position: fixed;
position-anchor: --tooltip-anchor;
top: anchor(bottom);
left: anchor(center);
translate: -50% 0;
margin-top: 8px;
}4. Anchor Position Options
The anchor() function accepts different keywords to reference various edges and positions of the anchor element.
Physical Position Values
Edge Values
anchor(top) - Top edge of anchoranchor(bottom) - Bottom edge of anchoranchor(left) - Left edge of anchoranchor(right) - Right edge of anchorCenter Values
anchor(center) - Center of anchor (works for both axes)Percentage-Based Positioning
You can use percentages to position at any point along the anchor's edge.
/* Position at 25% from the left edge of the anchor */
.tooltip {
left: anchor(25%);
}
/* Position at 75% from the left edge of the anchor */
.tooltip {
left: anchor(75%);
}
/* Same as anchor(center) */
.tooltip {
left: anchor(50%);
}Logical Position Values
For internationalization support, you can use logical properties that adapt to writing direction.
/* Logical values for inline axis (horizontal in LTR) */
anchor(start) /* Same as left in LTR, right in RTL */
anchor(end) /* Same as right in LTR, left in RTL */
/* Logical values for block axis (vertical) */
anchor(self-start) /* Same as top */
anchor(self-end) /* Same as bottom */The anchor-size() Function
Use anchor-size() to size an element based on the anchor's dimensions.
/* Match the width of the anchor */
.dropdown-menu {
position: fixed;
position-anchor: --dropdown-trigger;
top: anchor(bottom);
left: anchor(left);
/* Set width equal to anchor's width */
width: anchor-size(width);
}
/* Set minimum width to anchor's width */
.dropdown-menu {
min-width: anchor-size(width);
}
/* Use anchor's height */
.side-panel {
height: anchor-size(height);
}anchor-size() Values
anchor-size(width)- Anchor's widthanchor-size(height)- Anchor's heightanchor-size(block)- Block size (height in horizontal writing)anchor-size(inline)- Inline size (width in horizontal writing)5. Fallback Positioning
One of the most powerful features of CSS Anchor Positioning is automatic fallback positioning. When a positioned element would overflow the viewport, the browser can automatically try alternative positions.
The position-try-fallbacks Property
Define fallback positions that the browser should try if the primary position causes overflow.
/* Try flipping to opposite side if needed */
.tooltip {
position: fixed;
position-anchor: --my-anchor;
/* Primary position: below the anchor */
top: anchor(bottom);
left: anchor(center);
translate: -50% 0;
/* Fallback: flip to above if no room below */
position-try-fallbacks: flip-block;
}Built-in Flip Keywords
flip-blockFlips position in the block direction (top/bottom)
flip-inlineFlips position in the inline direction (left/right)
flip-startFlips start/end positions
flip-block flip-inlineFlips in both directions
The @position-try At-Rule
For more control, define custom fallback positions using @position-try.
/* Define custom fallback positions */
@position-try --bottom-right {
top: anchor(bottom);
left: anchor(right);
}
@position-try --top-center {
bottom: anchor(top);
left: anchor(center);
translate: -50% 0;
}
@position-try --left-center {
right: anchor(left);
top: anchor(center);
translate: 0 -50%;
}
.tooltip {
position: fixed;
position-anchor: --my-anchor;
/* Primary position */
top: anchor(bottom);
left: anchor(center);
translate: -50% 0;
/* Custom fallbacks in order of preference */
position-try-fallbacks: --top-center, --left-center, --bottom-right;
}The position-try-order Property
Control how the browser chooses between fallback options.
/* Try fallbacks based on available space */
.tooltip {
position-try-order: most-height; /* Prefer position with most vertical space */
}
.tooltip {
position-try-order: most-width; /* Prefer position with most horizontal space */
}
.tooltip {
position-try-order: most-block-size; /* Logical: most block space */
}
.tooltip {
position-try-order: most-inline-size; /* Logical: most inline space */
}Tip: Combine position-try-fallbacks withposition-try-order to create smart tooltips that always position themselves in the most visible location.
JavaScript Fallback for Unsupported Browsers
// Feature detection for anchor positioning
const supportsAnchorPositioning = CSS.supports('anchor-name', '--test');
if (!supportsAnchorPositioning) {
// Use Floating UI, Popper.js, or custom positioning
import('floating-ui').then(({ computePosition }) => {
// Set up JavaScript-based positioning
});
}
// Or use CSS @supports
@supports (anchor-name: --test) {
.tooltip {
position: fixed;
position-anchor: --my-anchor;
top: anchor(bottom);
}
}
@supports not (anchor-name: --test) {
.tooltip {
/* Fallback static positioning */
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
}
}6. Practical Examples
Tooltip That Follows a Button
A classic tooltip that appears below a button on hover, with automatic flip to top if near the viewport edge.
<!-- HTML -->
<button class="tooltip-trigger">Hover me</button>
<div class="tooltip" popover>
This is helpful tooltip text!
</div>/* CSS */
.tooltip-trigger {
anchor-name: --tooltip-trigger;
}
.tooltip {
position: fixed;
position-anchor: --tooltip-trigger;
/* Position below the button */
top: calc(anchor(bottom) + 8px);
left: anchor(center);
translate: -50% 0;
/* Flip to top if no room below */
position-try-fallbacks: flip-block;
/* Styling */
background: #1f2937;
color: white;
padding: 8px 12px;
border-radius: 6px;
font-size: 14px;
white-space: nowrap;
/* Hide by default */
opacity: 0;
pointer-events: none;
transition: opacity 0.2s;
}
/* Show tooltip on hover */
.tooltip-trigger:hover + .tooltip,
.tooltip-trigger:focus + .tooltip {
opacity: 1;
}Live Demo (Chrome 125+ only)
Hover over the button to see the tooltip. Try scrolling to see fallback positioning.
Dropdown Menu
A dropdown menu that matches the width of its trigger button and positions below it.
<!-- HTML -->
<div class="dropdown">
<button class="dropdown-trigger" popovertarget="menu">
Options
<svg><!-- chevron icon --></svg>
</button>
<ul id="menu" class="dropdown-menu" popover>
<li><a href="#">Profile</a></li>
<li><a href="#">Settings</a></li>
<li><a href="#">Sign out</a></li>
</ul>
</div>/* CSS */
.dropdown-trigger {
anchor-name: --dropdown;
}
.dropdown-menu {
position: fixed;
position-anchor: --dropdown;
/* Position below the trigger */
top: calc(anchor(bottom) + 4px);
left: anchor(left);
/* Match the width of the trigger */
min-width: anchor-size(width);
/* Flip above if no room below */
position-try-fallbacks: flip-block;
/* Styling */
margin: 0;
padding: 4px;
list-style: none;
background: white;
border: 1px solid #e5e7eb;
border-radius: 8px;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
}
.dropdown-menu li a {
display: block;
padding: 8px 12px;
color: #374151;
text-decoration: none;
border-radius: 4px;
}
.dropdown-menu li a:hover {
background: #f3f4f6;
}Live Demo (Chrome 125+ only)
Click the button to toggle the dropdown menu.
Popover Card
A rich popover card with multiple fallback positions for optimal visibility.
<!-- HTML -->
<span class="user-link" popovertarget="user-card">@johndoe</span>
<div id="user-card" class="user-popover" popover>
<img src="avatar.jpg" alt="John Doe" class="avatar" />
<h3>John Doe</h3>
<p>Frontend Developer at Acme Corp</p>
<button>Follow</button>
</div>/* CSS */
@position-try --above {
bottom: calc(anchor(top) + 8px);
left: anchor(center);
translate: -50% 0;
}
@position-try --right {
left: calc(anchor(right) + 8px);
top: anchor(center);
translate: 0 -50%;
}
@position-try --left {
right: calc(anchor(left) + 8px);
top: anchor(center);
translate: 0 -50%;
}
.user-link {
anchor-name: --user-link;
color: #3b82f6;
cursor: pointer;
}
.user-popover {
position: fixed;
position-anchor: --user-link;
/* Primary: below the link */
top: calc(anchor(bottom) + 8px);
left: anchor(center);
translate: -50% 0;
/* Try these positions if primary doesn't fit */
position-try-fallbacks: --above, --right, --left;
/* Choose position with most available space */
position-try-order: most-height;
/* Styling */
width: 280px;
padding: 16px;
background: white;
border-radius: 12px;
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
text-align: center;
}
.user-popover .avatar {
width: 64px;
height: 64px;
border-radius: 50%;
margin-bottom: 8px;
}
.user-popover h3 {
margin: 0 0 4px;
font-size: 16px;
font-weight: 600;
}
.user-popover p {
margin: 0 0 12px;
color: #6b7280;
font-size: 14px;
}
.user-popover button {
width: 100%;
padding: 8px 16px;
background: #3b82f6;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
}Context Menu with Arrow
A context menu with a pointer arrow that adjusts when the menu flips position.
/* CSS */
.context-trigger {
anchor-name: --context-anchor;
}
.context-menu {
position: fixed;
position-anchor: --context-anchor;
top: calc(anchor(bottom) + 8px);
left: anchor(center);
translate: -50% 0;
position-try-fallbacks: flip-block;
background: white;
border-radius: 8px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15);
padding: 8px;
}
/* Arrow pointing up (when menu is below) */
.context-menu::before {
content: '';
position: absolute;
top: -6px;
left: 50%;
translate: -50% 0;
border: 6px solid transparent;
border-bottom-color: white;
}
/* Arrow pointing down (when menu flips above) */
@position-try --flipped {
bottom: calc(anchor(top) + 8px);
left: anchor(center);
translate: -50% 0;
}
/* Rotate arrow when position changes */
.context-menu:has(:popover-open) {
/* Use :has() or JS to detect flipped state */
}Quick Reference
CSS Properties
CSS Functions
Flip Keywords
At-Rules
Feature Detection
Always check for browser support before relying on anchor positioning in production.
// JavaScript feature detection
if (CSS.supports('anchor-name', '--test')) {
console.log('Anchor positioning is supported!');
} else {
console.log('Falling back to JavaScript positioning');
// Use Floating UI, Popper.js, or Tippy.js
}
// CSS feature detection
@supports (anchor-name: --test) {
/* Anchor positioning styles */
}
@supports not (anchor-name: --test) {
/* Fallback positioning styles */
}Explore more CSS tools
CSS Grid Generator
Create grid layouts visually
CSS Flexbox Generator
Create flex layouts visually
CSS Gradient Generator
Create custom gradients
CSS Text Gradient
Gradient text effects
CSS Gradients Collection
275+ ready-to-use gradients
CSS Box Shadow Generator
Design multi-layer shadows
CSS Selection Generator
Style text highlight colors
CSS Scrollbar Generator
Style custom scrollbars
CSS Blend Mode Generator
Mix colors with blend modes
CSS Cursor Generator
Preview all cursor styles
CSS Loader Generator
Create loading animations
CSS Button Generator
Design buttons with hover effects
CSS Glow Generator
Create neon glow effects
Fluid Typography
Scale text across screen sizes
