npm package: @oddbird/css-anchor-positioning
Description: Polyfill for the proposed CSS anchor positioning spec
Author: OddBird
Latest version: 0.9.0

# CSS Anchor Positioning Polyfill

[![Build Status](https://github.com/oddbird/css-anchor-positioning/actions/workflows/test.yml/badge.svg)](https://github.com/oddbird/css-anchor-positioning/actions/workflows/test.yml) [![npm version](https://badge.fury.io/js/@oddbird%2Fcss-anchor-positioning.svg)](https://www.npmjs.com/package/@oddbird/css-anchor-positioning) [![Netlify Status](https://api.netlify.com/api/v1/badges/61a20096-7925-4775-99a9-b40a010197c0/deploy-status)](https://app.netlify.com/sites/anchor-polyfill/deploys)

<!-- [WPT results](https://anchor-position-wpt.netlify.app/) -->

- [Demo](https://anchor-positioning.oddbird.net/)
- [Draft Spec](https://drafts.csswg.org/css-anchor-position/)

The CSS anchor positioning
[specification](https://drafts.csswg.org/css-anchor-position/) 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.

## Browser Support

- Firefox 54+ (includes Android)
- Chrome 51 - 124 (includes Android)
- Edge 79 - 124
- Safari 10+ (includes iOS)

Anchor positioning was added to Chrome, Chrome Android, and Edge in Chromium
125, so the polyfill will not be applied to versions after 124. Some aspects of
anchor positioning were shipped later in Chromium, meaning that they are not
polyfilled and are not present in those versions.

- `position-try-fallbacks` was added in 128 after being renamed from
  `position-try-order`. Use both `-fallbacks` and `-order` or the `position-try`
  shorthand to make sure all versions are covered.
- `position-area` was added in 129.
- `anchor-scope` was added in 131.

## Getting Started

To use the polyfill, add this script tag to your document `<head>`:

```js
<script type="module">
  if (!("anchorName" in document.documentElement.style)) {
    import("https://unpkg.com/@oddbird/css-anchor-positioning");
  }
</script>
```

If you want to manually apply the polyfill, you can instead import the
`polyfill` function directly from the
`@oddbird/css-anchor-positioning/dist/css-anchor-positioning-fn.js` file.

For build tools such as Vite, Webpack, and Parcel, that will look like this:

```js
import polyfill from '@oddbird/css-anchor-positioning/fn';
```

The `polyfill` function returns a promise that resolves when the polyfill has
been applied.

You can view a more complete demo
[here](https://anchor-positioning.oddbird.net/).

## Configuration

The polyfill supports a small number of options. When using the default version
of the polyfill that executes automatically, options can be set by setting the
value of `window.ANCHOR_POSITIONING_POLYFILL_OPTIONS`.

```js
<script type="module">
  if (!("anchorName" in document.documentElement.style)) {
    window.ANCHOR_POSITIONING_POLYFILL_OPTIONS = {
      elements: undefined,
      excludeInlineStyles: false,
      roots: [document],
      useAnimationFrame: false,
    };
    import("https://unpkg.com/@oddbird/css-anchor-positioning");
  }
</script>
```

When manually applying the polyfill, options can be set by passing an object as
an argument.

```js
<script type="module">
  if (!("anchorName" in document.documentElement.style)) {
    const { default: polyfill } = await import("https://unpkg.com/@oddbird/css-anchor-positioning/dist/css-anchor-positioning-fn.js");

    polyfill({
      elements: undefined,
      excludeInlineStyles: false,
      roots: [document],
      useAnimationFrame: false,
    });
  }
</script>
```

### elements

type: `HTMLElements[]`, default: `undefined`

If set, the polyfill will only be applied to the specified elements instead of
to all styles. Any specified `<link>` and `<style>` elements will be polyfilled.
By default, all inline styles in the document will also be polyfilled, but if
`excludeInlineStyles` is true, only inline styles on specified elements will be
polyfilled.

### excludeInlineStyles

type: `boolean`, default: `false`

When not defined or set to `false`, the polyfill will be applied to all elements
that have eligible inline styles, regardless of whether the `elements` option is
defined. When set to `true`, elements with eligible inline styles listed in the
`elements` option will still be polyfilled, but no other elements in the
document will be implicitly polyfilled.

### roots

type: `(Document | HTMLElement)[]`, default: `[document]`

By default the polyfill applies to `document`, but you can configure one or more
shadow roots the polyfill should apply to using this option. See the
[shadow DOM examples](https://anchor-positioning.oddbird.net/shadow-dom) to learn
more.

### useAnimationFrame

type: `boolean`, default: `false`

Determines whether anchor calculations should [update on every animation
frame](https://floating-ui.com/docs/autoUpdate#animationframe) (e.g. when the
anchor element is animated using `transform`s), in addition to always updating
on scroll/resize. While this option is optimized for performance, it should be
used sparingly.

For legacy support, this option can also be set by setting the value of
`window.UPDATE_ANCHOR_ON_ANIMATION_FRAME`, or, when applying the polyfill
manually, by passing a single boolean with `polyfill(true)`.

## Limitations

While this polyfill supports many basic use cases, it doesn't (yet) support the
following features:

- The following portions of Position Fallback:
  - `position-try-order`. If `try-size` is specified in `position-try`
    shorthand, it will be parsed, and `try-tactics` will be applied, but the
    `try-size` will be ignored.
  - The `flip-start` `try-tactic` is only partially supported. The tactic is
    only applied to property names and anchor sides.
  - a `position-area` as a `try-tactic`
  - Fallback does not support percentage anchor-side values, nor anchor
    functions that are passed through custom properties.
- Polyfill allows anchoring in scroll more permissively than the spec allows,
  for instance without a default `position-anchor`.
- `anchor-scope` property on pseudo-elements
- `anchor-center` value for `justify-self`, `align-self`, `justify-items`, and
  `align-items` properties
- `position-visibility` property
- dynamically added/removed anchors or targets
- anchors and targets in separate shadow roots (see https://github.com/oddbird/css-anchor-positioning/issues/191)
- anchors or targets in constructed stylesheets
  (https://github.com/oddbird/css-anchor-positioning/issues/228)
- vertical/rtl writing-modes for anchor functions (partial support)
- implicit anchors or the `position-anchor: auto` keyword (pending resolution of
  https://github.com/whatwg/html/pull/9144)
- `position-area` is polyfilled by adding a wrapping element around the target,
  which adds a few differences:
  - This breaks selectors that rely on a direct relationship with the target,
    for instance `~ target`, `+ target`, `> target` or using `:nth` selectors.
  - Overflow alignment is not applied for a target that overflows its
    inset-modified containing block but would still fit within its original
    containing block. In other words, a polyfilled target may be placed in a
    `position-area` grid section outside its containing block, where the
    implementation would move the target inside the containing block.

In addition, JS APIs like `CSSPositionTryRule` or `CSS.supports` will not be
polyfilled.

### Inline styles

Browsers provide some validation for imperatively setting inline styles.
`el.style.color = "foo"` and `el.style.foo = "bar"` do not change the inline
styles of `el`. This is problematic for this polyfill, as we would like to
support `el.style.anchorName = "--foo"`, but that won't work in browsers that
don't support the `anchor-name` property.

While `el.setAttribute('style', 'anchor-name: --foo')` or `<div
style="anchor-name: --foo" />` both work, developers are often using tools that
generate the DOM. Both React and Vue use methods that remove the unknown inline
style properties at runtime.

If you are using inline styles to set anchor-related properties and the polyfill
isn't working, verify that the inline styles are actually showing up in the DOM.

### Invalid CSS

Some types of invalid CSS will cause the polyfill to throw an error. In these
cases, the polyfill will report any parse errors encountered in the console as
warnings. This will be followed by the error thrown by the polyfill.

The polyfill can't determine which parse error caused the polyfill error, but
please resolve any reported parse errors before opening a bug. We also recommend
using a CSS linter like [Stylelint](https://stylelint.io/) or
[@eslint/css](https://github.com/eslint/css).

## Sponsor OddBird's OSS Work

At OddBird, we love contributing to the languages & tools developers rely on.
We're currently working on polyfills
for new Popover & Anchor Positioning functionality,
as well as CSS specifications for functions, mixins, and responsive typography.
Help us keep this work sustainable
and centered on your needs as a developer!
We display sponsor logos and avatars
on our [website](https://www.oddbird.net/polyfill/#open-source-sponsors).

[Sponsor OddBird's OSS Work](https://github.com/sponsors/oddbird)