Introduction
Positioning a tooltip sounds simple. Put a small box next to a button. Done. But anyone who has built one knows that it can quickly turn into a cascade of challenges: `position: absolute`, complex coordinate calculations, listening for resize events, handling scrolling, checking screen boundaries, and often pulling in entire positioning libraries. Modern CSS is changing that paradigm.
CSS Anchor Positioning is emerging as a native browser feature that allows us to position one element relative to another directly in CSS, effectively eliminating the need for JavaScript positioning hacks. This capability is set to streamline the development of common UI components like tooltips, dropdown menus, and popovers.
What Is CSS Anchor Positioning?
At its core, CSS Anchor Positioning allows one element to serve as an anchor, while another element, the anchored element, positions itself in relation to that anchor. This fundamentally changes how developers approach complex UI layouts. Instead of JavaScript intercepting events and recalculating positions, the browser handles the layout natively.
Consider the common tooltip pattern. Traditionally, a tooltip is an absolutely positioned element whose `top` and `left` properties are calculated based on the trigger element's position and dimensions. This calculation must be re-run whenever the page scrolls, the window resizes, or the anchor element moves. This often leads to janky animations, performance issues, and reliance on JavaScript libraries like Popper.js or Tippy.js. Anchor Positioning aims to make these scenarios declarative and performant.
The Mechanics: Anchors and Anchor-Coupling
The system involves two key concepts: the anchor and the anchored element. The anchor is the element that the other element will be positioned relative to. The anchored element uses specific CSS properties to define its relationship with the anchor.
To establish an anchor, you use the anchor-name property on the anchor element. This property assigns a unique name to the anchor within its containing block. For example:
.tooltip-trigger {
anchor-name: --my-anchor;
}
The anchored element then uses the position-anchor property to specify which anchor it should relate to. This property essentially links the anchored element to a named anchor. If position-anchor is not explicitly set, it defaults to the nearest ancestor anchor.
The actual positioning is defined using anchor() function within properties like top, left, right, bottom, inset, translate, and transform. The anchor() function takes the anchor name and an optional side or corner of the anchor element to position against. For instance, to position the top-left corner of the tooltip relative to the bottom-center of the anchor:
.tooltip {
position: absolute;
top: anchor(--my-anchor, bottom);
left: anchor(--my-anchor, center);
transform: translate(0, 5px); /* Offset slightly */
}
This declarative approach means the browser calculates and updates the tooltip's position automatically when necessary, such as during scrolling or resizing, without developer intervention or JavaScript event listeners.
Building a Simple Tooltip
Let's walk through a practical example. We have a button that serves as the anchor for a tooltip element.
HTML Structure
The HTML would look something like this:
<div class="tooltip-container">
<button class="tooltip-trigger">Hover over me</button>
<div class="tooltip">This is a helpful tooltip!</div>
</div>
CSS Implementation
The CSS would then define the relationships and styling:
.tooltip-container {
position: relative; /* Needed for absolute positioning of tooltip */
display: inline-block;
}
.tooltip-trigger {
anchor-name: --tooltip-anchor;
padding: 10px;
border: 1px solid #ccc;
background-color: #f9f9f9;
}
.tooltip {
position: absolute;
/* Position the tooltip's top-left corner 5px below the anchor's bottom-center */
top: anchor(--tooltip-anchor, bottom);
left: anchor(--tooltip-anchor, center);
transform: translate(-50%, 5px); /* Center the tooltip horizontally and add vertical offset */
background-color: #333;
color: white;
padding: 8px 12px;
border-radius: 4px;
font-size: 0.9em;
white-space: nowrap;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0.3s ease;
}
.tooltip-container:hover .tooltip {
opacity: 1;
visibility: visible;
}
In this example, the .tooltip-trigger button is designated as the anchor with anchor-name: --tooltip-anchor;. The .tooltip element is positioned absolutely. Its top property is set to the bottom edge of the anchor (anchor(--tooltip-anchor, bottom)), and its left property is set to the horizontal center of the anchor (anchor(--tooltip-anchor, center)). The transform: translate(-50%, 5px); then shifts the tooltip horizontally to be centered above its anchor and provides a small vertical offset downwards. The hover state makes the tooltip appear.
Referenced Sources
- verified
