How to use CSS anchor positioning
Tags: css, webdev
Published: 2023-11-28 18:50:58

**Written by [Sebastian Weber](https://blog.logrocket.com/author/sebastianweber/)✏️**

The 2023 [State of CSS](https://2023.stateofcss.com/) survey revealed that the feature most respondents added to their reading lists was [anchor positioning](https://2023.stateofcss.com/en-US/features/layout/#anchor_positioning), and in particular, the layout feature was what most participants knew the least about and had the least practical experience with. 

Thus, this article's goal is to introduce this new layout technique to frontend developers.

## What is anchor positioning in CSS?

The introduction of the [official W3C specification](https://drafts.csswg.org/css-anchor-position/), currently in an experimental stage, strongly suggests that this API was proposed because of the limitations associated with absolute positioning. 

Anchor positioning is based on the existing CSS concept of absolute positioning. It adds to the idea of tethering elements together by placing one element, A, relative to another element, B. Throughout this article, I refer to B as the “anchor element” and A as the “anchor target element.” 

Anchor positioning will enable more flexible element tethering, which was previously only possible with a combination of absolute positioning and JavaScript. With this new approach, your tethering code stays within the CSS layer and no longer requires JavaScript code, which may improve performance.

## Browser support for anchor positioning

As of November 2023, this feature is still a draft and browser support is not yet widespread. Chrome Canary provides the most support behind a feature flag — visit `chrome://flags` and then go to **Experimental Web Platform features** to enable this flag: ![Experimental web platform features flag](https://blog.logrocket.com/wp-content/uploads/2023/11/experimental-web-platform-features-flag.png) If you do not enable this flag, you may not be able to view all examples correctly in later sections! 

To check browser support, you can use the following `@supports` rule:

```css
@supports(anchor-name: --foo) {  /* ... */}
```

Speaking of browser support, [CanIUse does not feature anchor positioning yet](https://github.com/Fyrd/caniuse/issues/6471).

### Using an anchor positioning polyfill

Even with limited native browser support, you already have good options to use it with a polyfill. All CodePens in this article [use this polyfill](https://github.com/oddbird/css-anchor-positioning) to upgrade browser support. 

Unfortunately, not all examples in this article work well with this polyfill, but do work with Chrome Canary when the feature flag is activated. Check the [list of the polyfill’s limitations](https://github.com/oddbird/css-anchor-positioning#limitations) before getting started. You can also [browse the supported scenarios](https://anchor-polyfill.netlify.app/) in the polyfill's demo page. 

In this article, you’ll learn how to tether elements to anchor elements with different techniques. Since anchor positioning is still a work in progress, API functions might change or get removed over time. As an example, other articles have showcased an anchor-scroll function, but I couldn't get this function to work even with the most recent Chrome Canary version. We’ll mainly focus on the functions that do work as a result.

## Example CodePens

All examples we provide are CodePens using polyfills for anchor positioning and the [Popover API](https://blog.logrocket.com/comparing-popover-api-dialog-element/) by embedding shared CSS and JS from [this base CodePen](https://codepen.io/doppelmutzi/pen/yLGWyKM). You will learn later that anchor positioning and the Popover API make a pretty powerful duo. 

Here is an overview of all examples:

*   [API playground](https://codepen.io/doppelmutzi/pen/PoVYEvy) showing physical and logical anchor-side properties and inset properties
*   [Vertical](https://codepen.io/doppelmutzi/pen/mdaYPYW)[ly](https://codepen.io/doppelmutzi/pen/mdaYPYW) [centered overlays](https://codepen.io/doppelmutzi/pen/mdaYPYW)
*   Cross-references with [inline styles and custom properties](https://codepen.io/doppelmutzi/pen/dywEGar)
*   [Tooltips](https://codepen.io/doppelmutzi/pen/VwqOMeJ) on hover and click with position fallback variants
*   [Cover elements](https://codepen.io/doppelmutzi/pen/LYMoZeW)
*   [Swapping anchor target element's positions](https://codepen.io/doppelmutzi/pen/RwEmNQO) and position-fallback rules
*   [Highlighting elements bi-directionally](https://codepen.io/doppelmutzi/pen/YzdbYLd)

## How does anchor positioning compare to absolute positioning?

The most obvious difference between anchor and absolute positioning is that you don't have to nest your anchor target element into the child tree of the anchor element (i.e., the element with `position: relative`). On the contrary, you can place your anchor target element anywhere in the DOM. 

Another advantage of this sophisticated CSS API is that it allows us to develop more robust designs that won’t "break" the tether between elements when the user interacts with the page. 

For example, let’s say we place a tooltip above an element that serves as an anchor. The tooltip will keep that position as long as it isn’t clipped by viewport bounds. Otherwise, a fallback mechanism takes over and shifts the tooltip below the anchor to make sure it is completely in sight of the user. 

In contrast to absolute positioning, where an absolutely positioned anchor target element is tethered to a relatively positioned ancestor element, anchor positioning provides more flexibility:

*   The anchor element can be located elsewhere in the DOM, even outside of the anchor target element's parent tree. Thus, anchors can be top-level elements
*   The Anchor Positioning API allows you to position and size anchor target elements in relation to anchor elements
*   You can describe fallback scenarios declaratively to guide the browser to change positioning in the event that anchor target elements would be clipped by viewport boundaries
*   You can position elements to multiple anchor elements, even dynamically, by using a math function

As an additional benefit, developers get more tools to alter the position and size of elements relative to these new anchor elements.

## How to tether elements with anchor positioning

The focus of this section is to describe the conceptual steps for using anchor-based positioning. In later sections, I’ll cover different aspects and facets of the API in more detail. The following CodePen shows [different methods of tethering](https://codepen.io/doppelmutzi/pen/dywEGar) elements together. The first approach is to use an implicit anchor element with an `anchor attribute`:

```html
<!-- anchor target element using anchor attribute -->
<div anchor="ref1 class="implicit-crossref">...</div>
<!-- anchor element -->
<sup id="ref1">1</sup>
```

An anchor element defines an ID that the anchor target element refers to, with the help of the `anchor` attribute. 

The next step is to define anchor-based positioning. Therefore, we make use of the [`anchor()` API function](https://drafts.csswg.org/css-anchor-position-1/#anchor-pos) to glue the anchor target element to its anchor element:

```css
.implicit-crossref {
 position: absolute;
 top: anchor(implicit start);
 /* ... */
}
```

First, we need to position the element absolutely. With that, we use the `anchor()` function to create the link between the anchor target element (referenced by the `.implicit-crossref` selector) and the anchor element that specifies the ID `ref1`. The `implicit` keyword does the trick. 

With `top: anchor(implicit start)`, we tell the browser to place the `top` position of the anchor target element to the position of the anchor element calculated by the `anchor()` function. `start` is one of many options we have to define the connection position of the anchor element, as the next diagram reveals: ![An overview of the anchor-side properties and the inset properties of the target](https://blog.logrocket.com/wp-content/uploads/2023/11/overview-anchor-side-properties-inset-properties-target.png) 

You can refer to different positions in the x- and y-axes with physical keywords (`top`, `left`, etc.), logical keywords (`start`, `center`, etc.), or percentages. From a terminology perspective, we should distinguish between the [inset properties](https://drafts.csswg.org/css-position-3/#insets) of the target element and the [anchor-side properties](https://drafts.csswg.org/css-anchor-position-1/#typedef-anchor-side) of the anchor element. 

Let's take a look at the next diagram, which illustrates how to position the anchor target element at the top right of the anchor element: ![How to target an element relative to its anchor](https://blog.logrocket.com/wp-content/uploads/2023/11/position-target-element-relative-anchor.png) The anchor target specifies the physical inset properties `top` and `left`, and uses logical anchor-side properties. 

The `#anchor-target` selector reveals another interesting aspect. The first argument of the `anchor()` function, `anchor-element`, is optional. Above, we used the `implicit` keyword, but in the previous example, we employed the concept of default anchors. Later, we’ll see an example where we define such an anchor with the `anchor-default` property.

### Logical inset properties vs. anchor-side properties

To make your CSS design more semantic, but especially prepared for changed writing modes, you have to understand logical inset properties and anchor-side properties. If you change the writing direction with the HTML `dir` attribute, you can use logical properties described in the next diagram: ![Diagram of logical anchor-side and inset properties](https://blog.logrocket.com/wp-content/uploads/2023/11/logical-anchor-side-inset-properties.png) The upper part of the diagram shows that `self-end` and `self-start` refer to the anchor target element in the `anchor()` function. So, `anchor(self-end)` would refer to the "left" side of the target element due to the right-to-left writing mode. But, `anchor(left)` would also refer to the left side of the anchor element. 

You can think of `self-start` and `self-end` like Flexbox's property `justify-self`, which allows a flex item to relatively align to itself. The example clarifies that the logical properties are semantic, since `self-end` refers always to the "arrow side" of the axis, whereas the physical representations (`left` and `right`) are not meaningful with a changed writing mode and might add to confusion. 

The lower part of the diagram emphasizes how to use logical inset properties to define the x and y coordinates of the target element that gets tethered to the anchor element. This example uses a RTL writing mode to show that the inset properties `inset-inline-start` and `inset-inline-end` get mapped logically to the x-axis. For the y-axis, you can use `inset-block-start` and `inset-block-end`. 

Here is what it looks like to tether an anchor target to the lower left of the anchor element with logical values only: ![Logical properties in action with a changed writing direction](https://blog.logrocket.com/wp-content/uploads/2023/11/logical-properties-action-changed-writing-mode.png)

Let's conclude the learnings of this section briefly before we look at the API in more detail:

*   An anchor target element needs to define `position: absolute` (or `fixed`, as we’ll see later)
*   An anchor target element can be tethered to an anchor element with the `anchor` attribute, and then has to use the `implicit` keyword in the `anchor()` function as the first argument
    *   As already indicated, the first argument can be omitted in the case of a default anchor. In addition, an anchor element can be specified with an explicit anchor name as the first argument
*   Finally, the anchor target element can be positioned relative to the anchor element by calculating the inset values (e.g., `top` and `left`) with the help of the `anchor()` function

## The Anchor Positioning API

The following are some crucial Anchor Positioning API properties and functions:

*   Declaring an anchor element with `anchor-name` or the `anchor` HTML attribute
*   Referencing an anchor element from the target element with dashed-ident anchor name (e.g., `--my-anchor`), `implicit` keyword, or indirectly with `anchor-default`
*   Anchor-based positioning with `anchor()` to tether elements together
*   Using `anchor-size()` to calculate the width and height of the target element with respect to the anchor's dimensions
*   Providing guidance to the browser with [`@position-fallback`](https://drafts.csswg.org/css-anchor-position-1/#fallback) to change the size and position of the target element when viewport boundaries clip the target element

### Declaring and referencing anchor elements

As described above, you can use a combination of an `id` attribute and an `anchor` attribute with the anchor element and the anchor target element, respectively. Then, you can use the `implicit` keyword as the first argument of `anchor()`. 

An alternative would be to use the `anchor-name` property to create an anchor element:

[See the CodePen](https://codepen.io/doppelmutzi/pen/LYMoZeW).

In the example, an overlay (the anchor target element) is positioned on top of an image element (the anchor element). With the following code, the anchor target element spans the dimensions of the image:

```css
#img {
 /* create an anchor named --cover */
 anchor-name: --cover;
}
#overlay {
 /* enable anchor positioning */
 position: absolute; 
  /* 
    tether the top left corner of the target 
    to the top left corner of the anchor, etc.
 */
 top: anchor(--cover top);
 bottom: anchor(--cover bottom);
 left: anchor(--cover left);
 right: anchor(--cover right);
}
```

With the `#img` selector, we create an anchor with the name `--cover`. It's important to use this dashed-ident naming convention, which should be familiar if you use custom properties. Omitting these double dashes breaks the connection. 

The target element selected by `#overlay` uses the anchor name as the first argument of every invocation of `anchor()`. You can also do this more concisely with the [`auto-same` anchor-side keyword](https://drafts.csswg.org/css-anchor-position-1/#typedef-anchor-side):

```css
#overlay-autosame {
 position: absolute;
 inset: anchor(--cover-autosame auto-same);
}
```

![Using a one-liner with inset properties and auto-same](https://blog.logrocket.com/wp-content/uploads/2023/11/one-liner-inset-auto-same.gif) As you see, you can reduce four lines into one using the [inset shorthand](https://drafts.csswg.org/css-logical-1/#propdef-inset). 

I've already indicated that the first argument of `anchor()`, the `anchor-element` specifier, is optional:

[See the CodePen](https://codepen.io/doppelmutzi/pen/RwEmNQO).

The CodePen above shows an example of [`anchor-default`](https://drafts.csswg.org/css-anchor-position-1/#anchor-default). This property defines the default anchor element for all invocations of `anchor()` on the anchor target element:

```css
/*
anchor target element that specifies 
--hero-image-1 as default anchor for all
calls of anchor() 
*/
figcaption {
 /* ... */
 anchor-default: --hero-image-1;
 bottom: anchor(auto);
 left: anchor(left);
}
```

You might be wondering what the keyword `auto` means. We will take a look at it in the next section when I talk about fallback position scenarios.

### Sizing target elements with respect to anchor elements

[`anchor-size()`](https://drafts.csswg.org/css-anchor-position-1/#funcdef-anchor-size) is a function with the same signature as `anchor()`. There are physical (`width` and `height`), logical (e.g., `block`), and `anchor-side` keywords that refer to the width and height of the anchor element. The return value of `anchor-size()` is a length value:

[See the CodePen](https://codepen.io/doppelmutzi/pen/mdaYPYW
).

The following code calculates the width of the target element in relation to the anchor element. The width is half of the width of the anchor element. It also shows that you can use custom properties with API functions, too:

```css
  /*
    The name of the anchor element is provided with a custom property.
  */
 width: calc(anchor-size(var(--anchor-inset) width) / 2);
```

## Anchor positioning in action

The rest of the article shows different, somewhat advanced use cases for leveraging the Anchor Positioning API and how to combine its different functions and properties.

### Fallback position scenarios

In this scenario, we:

*   Auto-swap target elements with the `auto` keyword of `anchor()`
*   Provide more guidance with `@position-fallback` rule

The following recording shows a major advantage of anchor positioning over absolute positioning. Using pure CSS, it's now possible to add hints to the browser to change the positions of anchor target elements if they no longer fit into the viewport during user interaction (i.e., resizing or scrolling): ![The figcaption is positioned above or below the image, depending on the available space](https://blog.logrocket.com/wp-content/uploads/2023/11/figcaption-above-below-image.gif) The `figcaption` switches between being above or below the image, dependent on the available space. Here is the code:

[See the CodePen](https://codepen.io/doppelmutzi/pen/RwEmNQO
).

```css
#caption-auto-swap img {
 anchor-name: --hero-image-1;
}
#caption-auto-swap figcaption {
 position: fixed; 
 anchor-default: --hero-image-1;
 bottom: anchor(auto);
 left: anchor(left);
 padding: .25em 0;
```

The `figcaption` has a `fixed` position, which makes it so that the anchor target element can live anywhere in the DOM. Our example makes use of `auto` for the `bottom` inset property and leaves it to the browser to determine vertical positioning. 

The auto-swap takes place in the corresponding axis; in this case, the y-axis. For the left target position, no auto-swap mechanism is used.

### The `position-fallback` property

There is also a more advanced fallback mechanism with the [`position-fallback` property](https://drafts.csswg.org/css-anchor-position-1/#fallback-property). With this approach, you can provide more flexible guidance to the browser when it determines the position for different scenarios:

```css
#caption-with-fallback img {
  anchor-name: --hero-image-fallback;
}
#caption-with-fallback figcaption {
 position: fixed;
 anchor-default: --hero-image-fallback;
 position-fallback: --fallback1;
}
@position-fallback --fallback1 {
 @try {
   top: anchor(bottom);
   left: anchor(left);
}
 @try {
   bottom: anchor(top);
   left: anchor(left);
 }
}
```

Inside of a `@position-fallback` rule, you can specify multiple `@try` rules that are processed in the order of declaration. The above example is the counterpart of the auto-swap example. In other use cases, you can also define fallback positions for other inset properties.

### Displaying cross-references to the side

In this scenario, we:

*   Use multiple anchors to position elements
*   Combine the `anchor()` function with `calc()` to determine the inset properties of target elements
*   Use custom properties with API functions, e.g., inside of `anchor()`
*   Use different approaches to create and use anchors, such as with inline styles

[See the CodePen](https://codepen.io/doppelmutzi/pen/dywEGar).

This CodePen showcases different options for creating anchor elements and superscript numbers, with cross-references positioned at the same vertical height in the dark sidebar area: ![The cross-references are positioned to the side](https://blog.logrocket.com/wp-content/uploads/2023/11/cross-references-positioned-side.png) The first example uses the implicit `anchor` attribute:

```html
<!-- anchor target element -->
<div anchor="ref1" class="implicit-crossref">1 This is a cross-reference tethered to its anchor with an <em>implicit HTML anchor</em> attribute</div>
<!-- ... -->
<!-- elsewhere in the DOM -->
<sup id="ref1">1</sup>
```

Since we tether the anchor element with `id="ref1"` to the anchor target element with the `anchor` attribute at the HTML level, there is no more CSS code needed for this concern. The anchor target element, selected with `.implicit-crossref` uses the `implicit` keyword in the `anchor()` function used with `top`:

```css
.implicit-crossref {
  position: absolute;
 --ref-left-pos: calc(anchor(--content-container end) + 10px);
 top: anchor(implicit start);
 left: var(--ref-left-pos);
}
```

The code above also shows that the cross-reference is tethered to another anchor named `--content-container`, which refers to the `main` element:

```css
main {
  anchor-name: --content-container;
}
```

The `main` tag is the content container, and with `anchor(--content-container end)`, a cross-reference's `left` position is placed in relation to it. 

As you can see, it is also possible to use `anchor()` functions inside of mathematical functions, such as `calc()`. It's also fine to store the result of such a calculation in a custom property (`--ref-left-pos`). 

With the above code in place, cross-references are moved to the top position of the reference source part of the running text. Horizontally, the cross-references are positioned at the end of the `main` container with an additional `10px` to create a nice gap between it and the content column. 

Let's look at another pattern to create and find anchors. The markup shows that we make use of inline styles. It shows that the anchor elements define their names with `anchor-name` as inline styles. The target element defines a custom property as an inline style that stores the anchor's name (`--ref2`):

```html
  <!-- anchor target element -->
  <div class="crossref-inline" style="--anchor-target: --ref2">2 This is a cross-reference tethered to its anchor by defining the <em>anchor-name inline</em> </div>
  <!-- ... -->
  <!-- anchor element -->
  <sup style="anchor-name: --ref2">2</sup> 
```

With that HTML in place, calculating the `top` position of the target element with the `anchor()` function can be done with the custom property in scope: `top: anchor(var(--anchor-target) start)`:

```css
.crossref-inline {
 position: absolute;
 --ref-left-pos: calc(anchor(--content-container end) + 10px);
 top: anchor(var(--anchor-target) start);
 left: var(--ref-left-pos);
}
```

The following example demonstrates a slightly different variant:

```html
<!-- anchor target element -->
<div class="crossref-inline" style="--anchor-target: --ref3">3 This is a cross-reference tethered to its anchor utilizing <em>inline styles and custom properties</em></div>
<!-- ... -->
<!-- anchor element -->
<sup style="--anchor-name: --ref3">3</sup>
```

The difference is that the `sup` element specifies a custom property named `--anchor-name`, which is used in the following CSS to define the `anchor-name` value:

```css
sup[style*="--anchor-name:"] {
  anchor-name: var(--anchor-name);
}
```

### Sophisticated tooltips on hover

This is probably the coolest example because it uses the Popover API too. Here, we’ll cover:

*   Showing a target element when you hover or click on the anchor element
*   Combining the Popover API with the Anchor Positioning API to create new effects

[See the CodePen](https://codepen.io/doppelmutzi/pen/VwqOMeJ
).

The following recording displays how our tooltip (the anchor target element) will appear on hover over the anchor element: ![Displaying the anchor target element on hovering over the anchor](https://blog.logrocket.com/wp-content/uploads/2023/11/display-anchor-target-element-on-hovering-anchor.gif)  With the following markup, no JavaScript is needed to achieve our goal. The anchor target is nested into the anchor element:

```html
<span id="tip-1" class="tooltip-anchor">amet (hover tooltip)<span anchor="tip-1" class="tooltip">tooltip on hover - with implicit anchor attribute</span></span>
```

As we already learned, we can tether one element to an anchor element using the `anchor` attribute and the `implicit` keyword:

```css
.tooltip {
  display: none;

  position: absolute;
  left: calc(anchor(implicit right) + .25em);
 bottom: calc(anchor(implicit top) + .25em);
}
.tooltip-anchor:hover > .tooltip {
 display: initial;
}
```

Initially, the tooltip is not displayed (`display: none`). When a user hovers over the anchor element, the `display` property changes to show the tooltip. 

The above code is another example that `calc()` and `anchor()` are a good combo: in this case, it is used to add some horizontal and vertical spacing so that the anchor's upper right edge does not "touch" the target's bottom left edge.

### Advanced tooltips on click

When we want to show a tooltip on click, we need to incorporate the Popover API to keep a pure CSS approach. The recording also shows that we can position the popover (i.e., the tooltip) according to a fallback strategy, as we covered in a previous section: ![Display the anchor target element on click with the anchor fallback mechanism](https://blog.logrocket.com/wp-content/uploads/2023/11/display-anchor-target-element-on-click-anchor-fallback-mechanism.gif) Let's look at the markup first:

```html
<!-- the anchor element and popover target -->
<button class="tooltip-anchor" id="tip-3" popovertarget="popover-1">Fermentum (click tooltip)</button>
<!-- ... -->
<!-- anchor target element and popover element
somewhere in the DOM -->
<div popover="auto"
 id="popover-1"
 anchor="tip-3"
>
 I'm a clickable tooltip w/o fallback positions (implicit anchor)
</div> 
```

From an anchor positioning perspective, this approach tethers the anchor element (`button`) to the target tooltip element (`div`) with the `anchor` attribute. 

To use the Popover API, the tooltip uses the `popover` attribute and defines an `id`. The anchor element is the popover target element at the same time and, therefore, has to specify the `popovertarget` attribute with a matching value. 

In contrast to the hover approach, the target element does not have to be a child element of its anchor element. As far as CSS is concerned, we don't need any more code to make the popover work. Just position the popover element, which represents the anchor target element simultaneously:

```css
#popover-1 {
  position: absolute;
  left: calc(anchor(implicit right) + .25em);
  bottom: calc(anchor(implicit top) + .25em);
}
```

The second popover example specifies a fallback strategy:

```css
#popover-2 {
 position: fixed;
 position-fallback: --fallback1;
}
@position-fallback --fallback1 {
   @try {
     bottom: calc(anchor(--tip4 top) + .25em);
     left: calc(anchor(--tip4 right) + .25em);
   }
   @try {
     top: calc(anchor(--tip4 bottom) + .25em);
     left: calc(anchor(--tip4 right) + .25em);
   }
}
```

Remember in some browsers, you need a polyfill to use the Popover API as of late 2023\. The above CodePen does this by using [shared styles and JavaScript](https://codepen.io/doppelmutzi/pen/yLGWyKM).

### Different approaches to vertical center overlays

This scenario focuses on:

*   Using `anchor-size()` to size a target element relative to its anchor element
*   Using the shorthand `inset` property to save some lines of CSS
*   Using `anchor()` in combination with and without `translate` and `transform` for vertical centering

The goal of this section is to place vertically-centered overlays on top of anchor elements: ![Vertically centered overlays on top of anchor elements](https://blog.logrocket.com/wp-content/uploads/2023/11/vertically-centered-overlays-anchor-elements.gif) The CodePen demonstrates different methods of achieving the same goal:

[See the CodePen](https://codepen.io/doppelmutzi/pen/mdaYPYW
).

For every example, an `img` tag represents the anchor element. In previous sections, we've seen multiple examples of creating anchors, so here, we’ll just look at the CSS code for the anchor target elements. 

The following shows how to use the [`inset` shorthand](https://developer.mozilla.org/en-US/docs/Web/CSS/inset) to define the top and left position with a one-liner. In order to stay DRY, we calculate the horizontal and vertical center of the anchor element with the `anchor()` and store it in the custom property `--center`:

```css
#img-overlay-inset {
 position: absolute;

 width: calc(anchor-size(var(--anchor-inset) width) / 2);
   --center: anchor(var(--anchor-inset) 50%);
   inset: var(--center) auto auto var(--center);

   translate: -50%;
   transform: translateY(-50%);
}
```

The example also shows that we calculate the width of the overlay with the help of the `anchor-size()` function. 

The anchor name is stored in the custom property `--anchor-inset`. With `calc(anchor-size(var(--anchor-inset) width) / 2)`, we make sure that the width of the overlay is always half the width of the anchor. 

Why do we need the last two lines? Without `translate` and `transform`, the overlay wouldn't be perfectly vertically centered: ![The overlay is not perfectly vertically centered](https://blog.logrocket.com/wp-content/uploads/2023/11/overlay-not-perfectly-vertically-centered.png)  We need to shift the overlay by 50 percent of its width to the left (`translate: -50%`) and 50 percent of its height to the top (`transform: translateY(-50%)`). Both CSS functions, `translate()` and `translateY()`, refer to the element where they are specified at, which comes in handy for our use case. 

The selector `#img-overlay-calc` demonstrates an example without relying on the above-mentioned CSS functions:

```css
#img-overlay-calc {
  position: absolute;
  --width: 300px;
  width: var(--width);
  --height: 50px;
  height: var(--height);

  top: calc(anchor(--picture-calc center) - var(--height) / 2);
  left: calc(anchor(--picture-calc 50%) - var(--width) / 2);
}
```

### Highlight elements on hover

Different from implementing tooltips on hover, in this section, we’ll:

*   Use elements as anchors and anchor target elements
*   Create bi-directional connections with inline styles, using inline variables as selectors

The recording below shows how we can use anchor positioning to hover over an element to highlight another element on the page with a border: ![Highlight other elements on the page on hover using anchor positioning](https://blog.logrocket.com/wp-content/uploads/2023/11/highlight-elements-on-page-on-hover.gif) The following CodePen represents a simple quiz, where you can hover over the questions to highlight the correct answer or to hover over the answers to highlight the corresponding questions:

[See the CodePen](https://codepen.io/doppelmutzi/pen/YzdbYLd).

The markup makes use of inline styles that define custom properties to create the relationships between questions and code listings. Every question and code listing defines `--is` and `--for` custom properties:

```html
<section id="questions">
 <p style="--is: --example1">
   <em style="--for: --code1">Question 1: Which code block tethers a target element to an HTML element using an anchor attribute?</em>
 </p>
 <!-- second question -->
</section>
<section id="code-listings">
 <pre style="--is: --code1; --for: --example1;">
   `
       .anchor-target {
         position: absolute;
         left: anchor(implicit right);
         bottom: anchor(implicit top);
       }
       ` </pre> <!-- second answer / code listing --> </section>
```

The following CSS tethers questions and answers bi-directionally, together:

```css
/* ... */
[style*="--is:"] {
 anchor-name: var(--is);
 cursor: help;
}
[style*="--for:"]:is(:hover, :focus-visible)::after {
 content: "";
 position: absolute;
 top: calc(anchor(var(--for) top) - var(--box-margin));
 right: calc(anchor(var(--for) right) - var(--box-margin));
 bottom: calc(anchor(var(--for) bottom) - var(--box-margin));
 left: calc(anchor(var(--for) left) - var(--box-margin));

 border: var(--box-border);
}
```

The above selectors target elements with `style` attributes, starting with a particular string. With `[style*="--is:"]`, we create anchor elements. With `[style*="--for:"]`, we select the anchor target elements that have stored the anchor name in the passed custom property `--for`. 

With `[style*="--for:"]:is(:hover, :focus-visible)::after`, we make use of a pseudo-element with empty content. However, we creatively built a box with a border by specifying the inset properties based on the anchor-side elements. By doing so, we position the bordered box on top of the anchor element creating an illusion of showing the border of the anchor element.

## Conclusion

Even though anchor positioning has not shipped in any browser by late 2023, you can use it today with a polyfill for some quite powerful use cases. Make sure to check the [limitations](https://github.com/oddbird/css-anchor-positioning), which will certainly become shorter over time. There is also some hope that this API can be used natively in 2024 — at least Chrome Canary offers very good support right now behind a feature flag. 

The advantages over absolute positioning are obvious:

*   No more third-party JS libraries or custom JS code required
*   You just provide guidance and delegate the responsibility to the browser
*   Performance is better because we use a native CSS feature
*   Improved DX
*   No wrapper elements are required, which improves semantics
*   More flexible, since the approach works with elements positioned anywhere on the page

Of course, it's still valid to use absolute positioning for its intended use cases.

---

## Is your frontend hogging your users' CPU?

As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, [try LogRocket](https://lp.logrocket.com/blg/css-signup).

[![LogRocket Signup](https://blog.logrocket.com/wp-content/uploads/2019/12/cpu-memory-usage.png)](https://lp.logrocket.com/blg/css-signup)

[LogRocket](https://lp.logrocket.com/blg/css-signup) is like a DVR for web and mobile apps, recording everything that happens in your web app, mobile app, or website. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.

Modernize how you debug web and mobile apps — [Start monitoring for free](https://lp.logrocket.com/blg/css-signup).