CSS Anchor Positioning Explained

Positioning a small popup next to a button sounds simple until you try to build it. A tooltip needs to stay close to the thing it explains, a menu should open under its button, and a help box may need to move if there is not enough space near the edge of the screen.

For years, this often meant JavaScript. You had to read the position of one element, calculate coordinates, and then move another element into place.

CSS Anchor Positioning gives us a native way to connect those two elements. According to MDN, the feature is available in current browsers, although older browser versions may still need a fallback.

The basic idea

First make one element an anchor:

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

Then another element can use that anchor:

.menu {
  position: absolute;
  position-anchor: --menu-button;

  top: anchor(bottom);
  left: anchor(left);
}

The menu is now positioned using the button. You no longer need JavaScript to ask for the button’s coordinates.

A simple example

<button class="help-button">
  Help
</button>

<div class="help-box">
  Here is some extra information.
</div>
.help-button {
  anchor-name: --help;
}

.help-box {
  position: absolute;
  position-anchor: --help;

  top: calc(anchor(bottom) + 0.5rem);
  left: anchor(left);

  padding: 1rem;
  border: 1px solid #ddd;
  background: white;
}

The important part is the connection between:

anchor-name: --help;

and:

position-anchor: --help;

What anchor() does

The anchor() function returns a position based on the anchor.

top: anchor(bottom);

means that the top of the floating element should line up with the bottom of the anchor.

You can also use:

left: anchor(left);
right: anchor(right);
top: anchor(top);
bottom: anchor(bottom);

Or add some space:

top: calc(anchor(bottom) + 0.75rem);

That is useful for menus, tooltips, and small floating panels.

Centering a tooltip

.tooltip {
  position: absolute;
  position-anchor: --target;

  left: anchor(center);
  transform: translateX(-50%);
}

This keeps the tooltip centered over the target.

Anchor positioning and popovers

Anchor Positioning works especially well with the HTML Popover API.

<button
  class="profile-button"
  popovertarget="profile-menu">
  Profile
</button>

<div
  id="profile-menu"
  class="profile-menu"
  popover>
  <a href="/profile/">Profile</a>
  <a href="/settings/">Settings</a>
</div>
.profile-button {
  anchor-name: --profile;
}

.profile-menu {
  position-anchor: --profile;

  top: calc(anchor(bottom) + 0.5rem);
  right: anchor(right);
}

HTML handles opening and closing. CSS handles where the popover appears.

What happens near the screen edge?

A menu that normally opens below a button may not fit when the button is close to the bottom of the screen.

Anchor Positioning includes fallback tools for cases like this.

A simple example is:

.menu {
  position-try-fallbacks: flip-block;
}

If the menu cannot fit in the preferred direction, the browser can try the opposite direction.

This is one of the big reasons Anchor Positioning is more useful than plain absolute positioning.

Why this used to need JavaScript

A common old approach looked like this:

const button = document.querySelector(".button");
const menu = document.querySelector(".menu");

const rect = button.getBoundingClientRect();

menu.style.left = `${rect.left}px`;
menu.style.top = `${rect.bottom + 8}px`;

Then you also had to think about scrolling, resizing, zooming, layout changes, and viewport edges.

The browser already knows where every element is, so letting CSS handle the relationship makes sense.

Use a fallback

A good fallback is to keep the interface usable even without anchor positioning.

.menu {
  position: absolute;
  top: 100%;
  right: 0;
}

@supports (anchor-name: --test) {
  .button {
    anchor-name: --button;
  }

  .menu {
    position-anchor: --button;
    top: calc(anchor(bottom) + 0.5rem);
    right: anchor(right);
  }
}

Older browsers get a normal absolutely positioned menu. Newer browsers get the better behaviour.

Good uses

Anchor Positioning is a good fit for:

The feature can become complex if you try to use everything at once, so I would start small.

.target {
  anchor-name: --target;
}

.popup {
  position: absolute;
  position-anchor: --target;
  top: calc(anchor(bottom) + 0.5rem);
  left: anchor(left);
}

That already solves one of the most common positioning problems on the web.

CSS Anchor Positioning is a good example of the browser taking over work developers used to repeat in JavaScript. For simple floating UI, that is a very welcome change.