CSS Anchor Positioning (Advanced): Position Elements Relative to Anchors

CSS Anchor Positioning lets you place one element relative to another element without using JavaScript for layout math. It is designed for things like tooltips, dropdowns, callouts, and floating labels that need to stay attached to a chosen anchor while the page scrolls or resizes.

Quick answer: Anchor positioning gives a positioned element a relationship to an anchor element, then lets CSS place that element using functions such as anchor() and anchor-size(). It is useful when you want CSS to handle anchored UI placement instead of measuring coordinates in script.

Difficulty: Advanced

You'll understand this better if you know: basic CSS positioning, the box model, and how position, inset, and stacking contexts work.

1. What Is CSS Anchor Positioning?

CSS Anchor Positioning is a set of positioning features that lets a “floating” element align itself to a named anchor element. The anchor can be a button, icon, input, or any other element that serves as the reference point for placement.

Think of the anchor as the element you point at, and the anchored box as the element that follows that point.

2. Why CSS Anchor Positioning Matters

Before anchor positioning, developers often used JavaScript to measure an element’s rectangle, calculate where another element should go, and update that placement on scroll or resize. That works, but it adds code, event handling, and maintenance.

Anchor positioning matters because it reduces layout glue code and keeps placement rules in CSS, where visual rules usually belong. It is especially useful for interface pieces that must stay near a trigger element while still avoiding collisions with the viewport or nearby content.

It is not a replacement for all layout. It solves a specific problem: positioning one element in relation to another element in a predictable, declarative way.

3. Basic Syntax or Core Idea

Anchor positioning uses two main ideas: declaring an anchor and then consuming that anchor from another element. The exact feature set is still advanced and can vary by browser support, but the core model is straightforward.

Declare an anchor

A reference element can expose an anchor name so other elements can position against it.

button {
  anchor-name: --trigger;
}

This means the button can act as the target for positioning rules used elsewhere.

Position a related element

The anchored element can refer to that name and use anchored offsets.

.tooltip {
  position: absolute;
  position-anchor: --trigger;
  inset-block-start: anchor(bottom);
  inset-inline-start: anchor(left);
}

The important idea is that the tooltip does not need hard-coded coordinates. It asks CSS to place it relative to the anchor’s box.

4. Step-by-Step Examples

Example 1: A tooltip below a button

This example places a tooltip underneath its trigger. The tooltip uses the anchor’s bottom edge for vertical placement and left edge for horizontal alignment.

button {
  anchor-name: --help-btn;
}

.tooltip {
  position: absolute;
  position-anchor: --help-btn;
  inset-block-start: calc(anchor(bottom) + 8px);
  inset-inline-start: anchor(left);
}

The tooltip sits just below the button with a small gap. The calc() function adds spacing without needing custom JavaScript measurements.

Example 2: A dropdown aligned to the right edge

Menus often need edge alignment so they line up with their trigger. Here the anchored panel aligns its inline end with the anchor’s inline end.

.menu-button {
  anchor-name: --menu;
}

.menu-panel {
  position: absolute;
  position-anchor: --menu;
  inset-block-start: anchor(bottom);
  inset-inline-end: anchor(right);
}

This pattern is useful when the menu should appear attached to the trigger’s edge rather than centered under it.

Example 3: Centering a popover on the anchor

Sometimes the best placement is centered horizontally over the anchor. You can combine anchor-based values with transforms or offset calculations.

.popover {
  position: absolute;
  position-anchor: --trigger;
  inset-block-start: anchor(bottom);
  inset-inline-start: anchor(center);
  transform: translateX(-50%);
}

The transform shifts the box back by half its own width so the centered anchor point becomes the visual center of the popover.

Example 4: Sizing to the anchor

Anchor positioning is not only about location. The size of the anchor can also be reused so related elements feel visually connected.

.badge {
  position: absolute;
  position-anchor: --avatar;
  inline-size: anchor-size(inline);
  block-size: anchor-size(block);
}

This is useful when a floating UI should match the trigger’s dimensions or grow in a controlled way based on it.

5. Practical Use Cases

These are all cases where the placement depends on another element’s position, not on the document flow alone.

6. Common Mistakes

Mistake 1: Forgetting to create the anchor name

Anchor positioning only works when the reference element actually exposes a matching anchor name. If the names do not match, the anchored element has nothing to attach to.

Problem: The tooltip refers to --help-btn, but the button never defines that anchor name, so the browser cannot resolve the position.

button {
  /* missing anchor-name */
}

.tooltip {
  position-anchor: --help-btn;
  inset-block-start: anchor(bottom);
}

Fix: Give the anchor element the same name that the floating element references.

button {
  anchor-name: --help-btn;
}

.tooltip {
  position-anchor: --help-btn;
  inset-block-start: anchor(bottom);
}

The corrected version works because both sides refer to the same anchor identity.

Mistake 2: Using anchor functions without a positioned element

Anchored placement still depends on normal CSS positioning rules. If the floating box is not positioned, the anchor-based offsets do not behave as expected.

Problem: The element uses anchor() values, but it is still participating in normal flow, so the offsets do not place it like a floating panel.

.tooltip {
  position-anchor: --help-btn;
  inset-block-start: anchor(bottom);
}

Fix: Use a positioned layout mode such as absolute or fixed when the element is meant to float.

.tooltip {
  position: absolute;
  position-anchor: --help-btn;
  inset-block-start: anchor(bottom);
}

The corrected version works because the tooltip is now treated as a positioned box that can be anchored.

Mistake 3: Expecting anchor positioning to fix overflow automatically

Anchor positioning helps place an element, but it does not automatically solve every collision problem. A tooltip can still overflow the viewport or be clipped by a container.

Problem: The element is positioned relative to the anchor, but there is no collision handling or fallback placement, so it may render off-screen.

.tooltip {
  position: absolute;
  position-anchor: --trigger;
  inset-block-start: anchor(bottom);
  inset-inline-start: anchor(left);
}

Fix: Add fallback placement logic and consider viewport-aware sizing or alternative alignment rules.

.tooltip {
  position: absolute;
  position-anchor: --trigger;
  inset-block-start: anchor(bottom);
  inset-inline-start: anchor(center);
  max-inline-size: min(90vi, 20rem);
}

The fixed version is more resilient because it reduces the chance of placing the box outside the visible area.

7. Best Practices

Use anchor names that describe the relationship

Choose names like --menu-trigger or --tooltip-target instead of vague names. Clear names make anchored layouts easier to maintain when a component has multiple floating parts.

.icon-button {
  anchor-name: --tooltip-target;
}

Descriptive anchor names help you understand what the relationship means without reading the whole stylesheet.

Keep the floating element visually close to the trigger

The feature works best when the anchored element appears to belong to the same interaction. Small offsets and consistent spacing make the UI easier to scan.

.tooltip {
  position-anchor: --tooltip-target;
  inset-block-start: calc(anchor(bottom) + 0.5rem);
}

A small, consistent gap reads as intentional and avoids visual crowding.

Use fallback sizing for constrained viewports

Anchored components can become too wide or too tall for a small screen. Add maximum sizes so they can adapt when space is tight.

.popover {
  max-inline-size: min(24rem, 90vi);
  overflow: auto;
}

This keeps the anchored box usable when the available space is smaller than expected.

8. Limitations and Edge Cases

One of the most common “not working” reports is that the box appears in the wrong place because another ancestor creates a clipping or containing context. In those cases, the anchor math may be correct, but the rendering context still prevents the element from being visible where you want it.

9. Practical Mini Project

This mini project shows a help icon with a tooltip that appears below it and stays aligned to the icon. The example is intentionally small but complete so you can see how the pieces fit together.

<div class="help-field">
  <button class="help-button" type="button">?
  <div class="tooltip">Enter a valid email address.</div>
</div>

.help-field {
  position: relative;
  padding: 2rem;
}

.help-button {
  anchor-name: --help;
  inline-size: 2rem;
  block-size: 2rem;
}

.tooltip {
  position: absolute;
  position-anchor: --help;
  inset-block-start: calc(anchor(bottom) + 0.5rem);
  inset-inline-start: anchor(left);
  padding: 0.5rem 0.75rem;
  background: #222;
  color: #fff;
  border-radius: 0.5rem;
}

The button becomes the anchor, and the tooltip uses that anchor to stay attached underneath it. In a real app, you would also add visibility rules and fallback behavior for unsupported browsers.

10. Key Points

11. Practice Exercise

Build an anchored info card that appears below a card title and stays aligned with the title when the content above it changes.

Expected output: A title with a small panel directly beneath it, aligned to the title’s start edge.

Hint: Use anchor-name on the heading and position-anchor plus anchor() on the panel.

Solution:

<section class="card">
  <h2 class="card-title">Product details</h2>
  <div class="info-panel">
    Free shipping on orders over $50.
  </div>
</section>

.card {
  position: relative;
  padding: 2rem;
}

.card-title {
  anchor-name: --card-title;
  margin: 0;
}

.info-panel {
  position: absolute;
  position-anchor: --card-title;
  inset-block-start: calc(anchor(bottom) + 0.5rem);
  inset-inline-start: anchor(left);
  max-inline-size: min(20rem, 90vi);
  padding: 0.75rem;
  background: #f3f4f6;
  border: 1px solid #d1d5db;
}

This solution keeps the panel tied to the heading without hard-coded pixel coordinates. It is a compact pattern you can adapt to badges, menus, and other anchored surfaces.

12. Final Summary

CSS Anchor Positioning is an advanced layout feature for attaching one element to another element in a declarative way. It is most valuable for floating UI such as tooltips, menus, and popovers, where the anchor should drive the final placement.

The core workflow is simple: define an anchor, point another element at it, and use anchor-based functions to calculate offsets or size. In practice, you still need to think about overflow, clipping, fallback behavior, and browser support.

If you already know CSS positioning well, anchor positioning is a powerful next step for building more resilient interface components with less script. A good next topic is the related set of CSS popover and positioning features that help manage floating interfaces together.