CSS Anchor Positioning Polyfill

Anchoring Elements Using CSS

The CSS anchor positioning specification defines anchor positioning, "where a positioned element can size and position itself relative to one or more 'anchor elements' elsewhere on the page." This CSS Anchor Positioning Polyfill supports and is based on this specification.

The proposed anchor() and anchor-size() functions add flexibility to how absolutely positioned elements can be placed within a layout. Instead of being sized and positioned based solely on the position of their containing block, the proposed new functions allow absolutely positioned elements to be placed relative to one or more author-defined anchor elements.

Positioning with anchor() [stylesheet]

Target
Anchor

With polyfill applied: Target and Anchor's right edges line up. Target's top edge lines up with the bottom edge of the Anchor.

#my-anchor-positioning {
  anchor-name: --my-anchor-positioning;
}

#my-target-positioning {
  position: absolute;
  top: anchor(--my-anchor-positioning bottom);
  right: anchor(--my-anchor-positioning right, 50px);
}

Positioning with anchor() [<style> tag]

Target
Anchor

With polyfill applied: Target is positioned at the top left corner of the Anchor.

/* a <style> tag */

#my-anchor-style-tag {
  anchor-name: --my-anchor-style-tag;
}

#my-target-style-tag {
  position: absolute;
  bottom: anchor(--my-anchor-style-tag start);
  right: anchor(--my-anchor-style-tag left);
}

Positioning with anchor() [inline styles]

Target
Anchor

With polyfill applied: Target and Anchor's right edges line up. Target's top edge lines up with the bottom edge of the Anchor.

/* inline <style> attributes */

/* anchor */

  style="anchor-name: --my-anchor-in-line"

/* target */

  style="
    position: absolute;
    top: anchor(--my-anchor-in-line bottom);
    right: anchor(--my-anchor-in-line right);
  "

Positioning with anchor() [implicit anchor attribute]

Anchor
Target

With polyfill applied: Target is positioned at the top left corner of the Anchor.

<div id="my-implicit-anchor">Anchor</div>
<div id="my-implicit-target" anchor="my-implicit-anchor">Target</div>

#my-implicit-target {
  position: absolute;
  right: anchor(implicit left);
  bottom: anchor(top);
}

Anchoring a popover

Popover (Target)

With polyfill applied: Target is positioned at the bottom right corner of the Anchor.

#my-anchor-popover {
  position: absolute;
  left: 200px;
  anchor-name: --my-anchor-popover;
}

#my-target-popover {
  position: absolute;
  left: anchor(--my-anchor-popover right);
  top: anchor(--my-anchor-popover bottom);
}

Positioning with anchor() [anchor name set as CSS custom property]

Anchor
Target

With polyfill applied: Target is positioned at the top left corner of the Anchor.

#my-anchor-name-prop {
  anchor-name: --my-anchor-name-prop;
}

#my-target-name-prop {
  --anchor-var: --my-anchor-name-prop;

  position: absolute;
  right: anchor(var(--anchor-var) left);
  bottom: anchor(var(--anchor-var) top);
}

Positioning with @position-fallback

@position-fallback Anchor
Target

With polyfill applied, the following positions are attempted in order:

  1. Align the bottom, left edge of the target with the top, left edge of the anchor.
  2. Align the top, left edge of the target with the bottom, left edge of the anchor.
  3. Align the bottom, right edge of the target with the top, right edge of the anchor.
  4. Align the top, right edge of the target with the bottom, right edge of the anchor, and increase the height and width of the target.
#my-anchor-fallback {
  anchor-name: --my-anchor-fallback;
}

#my-target-fallback {
  position: absolute;
  position-fallback: --fallback1;
}

@position-fallback --fallback1 {
  /* First try to align the bottom, left edge of the target
     with the top, left edge of the anchor. */
  @try {
    bottom: anchor(--my-anchor-fallback top);
    left: anchor(--my-anchor-fallback left);
  }

  /* Next try to align the top, left edge of the target
     with the bottom, left edge of the anchor. */
  @try {
    top: anchor(--my-anchor-fallback bottom);
    left: anchor(--my-anchor-fallback left);
  }

  /* Next try to align the bottom, right edge of the target
     with the top, right edge of the anchor. */
  @try {
    bottom: anchor(--my-anchor-fallback top);
    right: anchor(--my-anchor-fallback right);
  }

  /* Finally, try to align the top, right edge of the target
     with the bottom, right edge of the anchor. */
  @try {
    top: anchor(--my-anchor-fallback bottom);
    right: anchor(--my-anchor-fallback right);
    width: 100px;
    height: 100px;
  }
}

Positioning with anchor() [scrolling elements]

Anchor
Inner-anchored Target
Outer-anchored Target

With polyfill applied: The Inner-anchored Target is positioned at the top right corner of the Anchor. The Outer-anchored Target is positioned at the bottom left corner of the Anchor.

#scroll-anchor {
  anchor-name: --scroll-anchor;
}

#inner-anchored {
  position: absolute;
  bottom: anchor(--scroll-anchor top);
  left: anchor(--scroll-anchor end);
}

#outer-anchored {
  position: absolute;
  top: anchor(--scroll-anchor bottom);
  right: anchor(--scroll-anchor start);
}

Positioning with anchor() [used in calc() function]

Anchor
Target

With polyfill applied: Target's left edge is 50px left of the Anchor's right edge). The top edge of the Target is 50px above the bottom edge of the Anchor.

#my-anchor-math {
  anchor-name: --my-anchor-math;
}

#my-target-math {
  --full-math: anchor(--my-anchor-math 100%);
  --full-minus-math: calc(anchor(--my-anchor-math 100%) - 50px);

  position: absolute;
  top: calc(var(--full-math) - 50px);
  left: var(--full-minus-math);
}

Positioning with anchor() [passed through CSS custom property]

Anchor
Target

With polyfill applied: Target's top edge is positioned at 50% of the height of the Anchor. The right edge of the Target lines up with 100% of the width of the Anchor (i.e. the Anchor's right edge).

#my-anchor {
  anchor-name: --my-anchor;
}

#my-target {
  --center: anchor(--my-anchor 50%);
  --full: anchor(--my-anchor 100%);

  position: absolute;
  top: var(--center);
  right: var(--full);
}

Positioning with anchor() [passed through multiple CSS custom properties]

Anchor
Target

With polyfill applied: Target's left edge is positioned in Anchor's horizontal center. Target's bottom edge is 10% above the bottom edge of Anchor.

#my-anchor-props {
  anchor-name: --my-anchor-props;
}

#my-target-props {
  --half: anchor(--my-anchor-props 50%);
  --quarter: calc(var(--half) / 2);
  --tenth: calc(var(--quarter) / 2.5);

  position: absolute;
  left: var(--half);
  bottom: var(--tenth);
}

Positioning with anchor() [with duplicate CSS custom properties]

Anchor
Target

With polyfill applied: Target's top left corner is positioned in the center (vertically and horizontally) of the Anchor.

#anchor-duplicate-custom-props {
  anchor-name: --anchor-duplicate-custom-props;
}

#target-duplicate-custom-props {
  --center: anchor(--anchor-duplicate-custom-props 50%);

  position: absolute;
  top: var(--center);
  left: var(--center);
}

#other {
  --center: anchor(--anchor-duplicate-custom-props 100%);
}

Sizing with anchor-size()

Anchor
Target

With polyfill applied: Target has the same width as the Anchor.

#my-anchor-size {
  anchor-name: --my-anchor;
  width: 5em;
}

#my-target-size {
  width: anchor-size(--my-anchor width);
}

Dynamically update anchors

Anchor
Target

With polyfill applied: Target and Anchor's right edges line up. Target's top edge lines up with the bottom edge of the Anchor.

When Anchor width is changed dynamically, Target position updates accordingly.

#my-anchor-update {
  anchor-name: --my-anchor-update;
}

#my-target-update {
  position: absolute;
  right: anchor(--my-anchor-update right);
  top: anchor(--my-anchor-update bottom);
}