1. Prompt and Use Case
A price annotation follows a product card. Its inline start aligns with the card's content start, and its inline size matches the card. The relationship must survive left-to-right, right-to-left, and vertical writing modes. A list renders many card-and-annotation pairs, while another view stretches a range marker between two separate endpoints.
This question is about the CSS Anchor Positioning layout model: how an element becomes an anchor, how an absolutely positioned element selects a default anchor, how position and size functions resolve, and how name scope and containing blocks constrain the relationship. Viewport collision and floating-widget interaction are separate implementation topics.
2. What the Interviewer Is Testing
- Whether you understand that
anchor-nameexposes an anchor andposition-anchorselects a default anchor for a positioned element. - Whether you distinguish
anchor(), which resolves a position, fromanchor-size(), which resolves a length. - Whether you use logical insets and logical sizes for writing-mode support instead of fixing everything to
leftandright. - Whether you know that source order, tree scope, and
anchor-scopeaffect same-name matching. - Whether you inspect the positioned element's containing block because anchor values still participate in normal positioning calculations.
3. Clarifying Questions to Ask First
- Is the target
position: absoluteorposition: fixed, and which element establishes its containing block? - Is the relationship one-to-one, many targets to one anchor, or one target to several anchors?
- Does the page repeat components with the same names or cross a tree boundary such as Shadow DOM?
- Must the component support right-to-left and vertical writing modes? Should it copy a physical width or a logical inline size?
- What ordinary positioning value should apply if the named anchor is missing or unacceptable in the current context?
4. A 30-Second Answer Framework
Give the source element a dashed identifier with anchor-name, then make the target absolute or fixed and select that source with position-anchor. Use anchor() to read an anchor edge and anchor-size() to read a physical or logical dimension; the target's insets still resolve within its own containing block. Use inset-inline-*, inset-block-*, and inline-size for writing-mode support. Scope repeated names with anchor-scope, and name anchors explicitly inside functions when one target depends on several sources.
5. From an Anchor to Final Layout
Step 1: Establish an Explicit Anchor Relationship
The source exposes one or more names through anchor-name. The target must be absolutely or fixed positioned before position-anchor can select its default anchor:
.product-card {
anchor-name: --product-card;
}
.price-note {
position: absolute;
position-anchor: --product-card;
}position-anchor establishes only the default reference. It does not set an inset or replace the target's containing block. If the name cannot resolve to an acceptable anchor, dependent functions use their fallback or become invalid, so the ordinary positioning fallback still needs a predictable result.
Step 2: Read Position with anchor()
anchor() yields a length for an inset property, connecting one target edge to an anchor edge. Logical insets let the same rule follow different writing modes:
.price-note {
position: absolute;
position-anchor: --product-card;
inset-block-start: anchor(end);
inset-inline-start: anchor(start);
}Here, start and end resolve on the relevant axis. To reference something other than the default anchor, put its name directly in the function, such as anchor(--sidebar end). Explicit names let different properties on one target depend on different sources.
Step 3: Build Size Relationships with anchor-size()
anchor-size() returns a physical or logical dimension, not a coordinate. An annotation can copy the card's logical width like this:
.price-note {
inline-size: anchor-size(inline);
max-inline-size: min(32rem, anchor-size(inline));
}width and height fit explicitly physical relationships; inline and block fit components that follow writing mode. The function can also participate in calc(), for example to derive spacing from part of the anchor's inline size. It supplies a length only; the element's position still follows absolute-positioning rules.
Step 4: Reference More Than One Anchor
A range marker can associate with the start as its default anchor while explicitly reading the end in another inset:
.range-start { anchor-name: --range-start; }
.range-end { anchor-name: --range-end; }
.range-band {
position: absolute;
position-anchor: --range-start;
inset-inline-start: anchor(--range-start center);
inset-inline-end: anchor(--range-end center);
}The positioned element still has only one associated default anchor through position-anchor; other names can participate in position calculations through anchor(). That default association also affects behavior such as scroll attachment. Both inset values enter the target's containing-block equation, so the design must define fallbacks for missing, crossed, or unacceptable anchors.
Step 5: Scope Repeated Anchor Names
If every repeated component declares --item, an unscoped positioned element may match the last acceptable anchor in source order. anchor-scope limits the same name to a component subtree:
.result-row {
anchor-scope: --item;
}
.result-row__value { anchor-name: --item; }
.result-row__note {
position: absolute;
position-anchor: --item;
inset-inline-start: anchor(end);
}This controls name visibility. It cannot force a reference across tree scopes, and it does not establish a containing block. The component still needs a deliberate positioned ancestor.
Step 6: Include the Containing Block in the Model
The position returned by anchor() is converted into a length usable by the target inset, but the target is still laid out by its own absolute-positioning containing block. Switching between absolute and fixed, moving the target in the DOM, or establishing a new positioning context on an ancestor can change the result. When placement is wrong, inspect the target's containing block before debugging anchor matching.
6. High-Quality Sample Answer
Anchor Positioning first relates a source element to a positioned target. The source declares a name withanchor-name; an absolute or fixed target selects its default source withposition-anchor.anchor()supplies a position to an inset, whileanchor-size()supplies a physical or logical dimension. I use logical insets andinline-sizefor right-to-left or vertical writing. A target that needs two sources selects one default association and names each source inside the relevantanchor(); repeated list components useanchor-scopeto isolate the same name. I also verify the target's containing block, because anchor functions do not bypass the absolute-positioning model.
7. Common Mistakes
- Declare only
anchor-nameand expect movement → no positioned relationship exists yet → make the target absolute or fixed and reference the name. - Treat
anchor()as a sizing function → position and dimension responsibilities become confused → useanchor()for edges andanchor-size()for dimensions. - Hard-code
leftandwidth→ right-to-left or vertical writing reverses the intended relationship → choose logical insets and logical sizes. - Reuse one name across list items without scope → targets follow the last same-name anchor → set
anchor-scopeon each component container. - Treat
anchor-scopeas a containing block → matching is correct but coordinates are still wrong → inspect the positioned ancestor separately. - Set one default
position-anchorfor a multi-anchor target → other properties still read the wrong source → name each source explicitly in itsanchor().
8. Follow-up Questions and Responses
Follow-up 1: How does anchor() differ from position-area?
anchor() turns a specific anchor edge into a length for an inset, which is useful for precise edge-to-edge relationships. position-area places the target in an area grid centered on the anchor, which expresses a broader placement region. They belong to the same model but solve at different levels.
Follow-up 2: Does anchor-size() make the target follow anchor movement?
No. It calculates a length. Position tracking comes from anchor(), position-area, or another positioning rule. Setting only inline-size: anchor-size(inline) synchronizes logical size, not location.
Follow-up 3: What happens when several elements share one anchor-name?
The target selects an acceptable anchor according to the matching rules, so repeated components can all resolve to a later same-name source. Scope the name inside each component with anchor-scope, or give instances explicit distinct names.
Follow-up 4: Why can the target be offset when the anchor is correct?
Its insets still participate in absolute positioning. The containing block, writing mode, margins, and target size all affect the final result. Inspect the target's containing block first, then verify its default anchor and each function's resolved value.