Only Chris, right? You’ll want to view this in a Chromium browser:

This is exactly the sort of thing I love, not for its practicality (cuz it ain’t), but for how it illustrates a concept. Generally, tutorials and demos try to follow the “rules” — whatever those may be — yet breaking them helps you understand how a certain thing works. This is one of those.

The concept is pretty straightforward: one target element can be attached to multiple anchors on the page.

<div class="anchor-1"></div>
<div class="anchor-2"></div>
<div class="target"></div>

We’ve gotta register the anchors and attach the .target to them:

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

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

.target {
  
}

Wait, wait! I didn’t attach the .target to the anchors. That’s because we have two ways to do it. One is using the position-anchor property.

.target {
  position-anchor: --anchor-1;
}

That establishes a target-anchor relationship between the two elements. But it only accepts a single anchor value. Hmm. We need more than that. That’s what the anchor() function can do. Well, it doesn’t take multiple values, but we can declare it multiple times on different inset properties, each referencing a different anchor.

.target {
  top: anchor(--anchor-1, bottom);
}

The second piece of anchor()‘s function is the anchor edge we’re positioned to and it’s gotta be some sort of physical or logical insettop, bottom, start, end, inside, outside, etc. — or percentage. We’re bascially saying, “Take that .target and slap it’s top edge against --anchor-1‘s bottom edge.

That also works for other inset properties:

.target {
  top: anchor(--anchor-1 bottom);
  left: anchor(--anchor-1 right);
  bottom: anchor(--anchor-2 top);
  right: anchor(--anchor-2 left);
}

Notice how both anchors are declared on different properties by way of anchor(). That’s rad. But we aren’t actually anchored yet because the .target is just like any other element that participates in the normal document flow. We have to yank it out with absolute positioning for the inset properties to take hold.

.target {
  position: absolute;

  top: anchor(--anchor-1 bottom);
  left: anchor(--anchor-1 right);
  bottom: anchor(--anchor-2 top);
  right: anchor(--anchor-2 left);
}

In his demo, Chris cleverly attaches the .target to two <textarea> elements. What makes it clever is that <textarea> allows you to click and drag it to change its dimensions. The two of them are absolutely positioned, one pinned to the viewport’s top-left edge and one pinned to the bottom-right.

If we attach the .target's top and left edges to --anchor-1‘s bottom and right edges, then attach the target's bottom and right edges to --anchor-2‘s top and left edges, we’re effectively anchored to the two <textarea> elements. This is what allows the .target element to stretch with the <textarea> elements when they are resized.

But there’s a small catch: a <textarea> is resized from its bottom-right corner. The second <textarea> is positioned in a way where the resizer isn’t directly attached to the .target. If we rotate(180deg), though, it’s all good.

Again, you’ll want to view that in a Chromium browser at the time I’m writing this. Here’s a clip instead if you prefer.

That’s just a background-color on the .target element. We can put a little character in there instead as a background-image like Chris did to polish this off.

Fun, right?! It still blows my mind this is all happening in CSS. It wasn’t many days ago that something like this would’ve been a job for JavaScript.


Multiple Anchors originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.