diff --git a/content/blog/2026/anchor-overflow.md b/content/blog/2026/anchor-overflow.md new file mode 100644 index 000000000..11cbb3bad --- /dev/null +++ b/content/blog/2026/anchor-overflow.md @@ -0,0 +1,375 @@ +--- +title: Handling overflow with anchor positioning +sub: What is safer than safe? +date: 2026-01-22 +image: + src: blog/2026/anchor-overflow.jpg + alt: > + A small blue house + perched precariously, + overhanging the edge of a concrete base. +author: james +sponsors: true +tags: + - Article + - Anchor Positioning + - CSS +related_tag: Anchor Positioning +summary: | + When you use `position-area`, the most obvious impact is that you are setting an + area in which to place the anchored element. But what happens when the area + isn't the exact size as the element you're trying to place? +--- + + + +{% callout 'note', false %} + +**A note on the demos** + +These demos use a range input as an easy movable element. While movement isn't +required for anchor positioning, it's useful for demos to show how it works in a +variety of situations. Unfortunately, Firefox doesn't yet support using the +thumb as an anchor, and there is an [open +bug](https://bugzilla.mozilla.org/show_bug.cgi?id=1993699). + +Also, the CSS shown with each demo is editable, so play around to see what's +going on! + +{% endcallout %} + +Anchor positioning handles this by applying self alignment values to position +the element close to the anchor. You likely are familiar with these values from +using them in grid layouts. + + + + + +There are many possible values for `position-area`, but they are essentially +different ways of specifying which areas you want to pick within a 3x3 grid. On +each axis, you have a start, center, and end area. You can pick any combination +except for start and end without the center, as it has to be contiguous. + +For an in-depth look at `position-area`, check out my [article on +`position-area`](/2025/02/25/anchor-position-area/). + +## Alignment rules + +There are just 3 rules that determine what alignment is used, based on the value +of the `position-area` that you specified. + +### Rule #1: center + +For each axis, if `position-area` only specifies the `center` track, then the +alignment is `center`. + + + + + +### Rule #2: anchor-center + +If `position-area` specifies all three sections in the axis, then the alignment +is `anchor-center`. + + + + + +Wait -- what is `anchor-center`? It's a new value for the self alignment +properties that aligns to the center of the anchor element. This differs from +`center`, which aligns to the center of the new containing block created by +`position-area`. + +### Rule #3: everything else + +The final case for `position-area` is that it specifies just two of the sections +on the axis. In other words, it selects one edge, and perhaps the center, but +not the other edge. In this situation, the alignment is whatever puts it closest +to the anchor. + + + + + +{% callout 'note', false %} + +Of course, the spec isn't just "whatever puts it closest". The spec says that +the alignment is "toward the non-specified side track". So if you specify +"start" or "start and center", then the alignment will be `end`, and if you +specify "end" or "end and center", then the alignment will be `start`. + +While I find this to be technically useful, it doesn't really help my mental +model of how this works, so I just think of it as "whatever is closest". + +{% endcallout %} + +## Overriding the defaults + +But these are just the default values, and you can choose to override them. I +haven't seen compelling use cases for this, but I'm guessing someone will come +up with one. Probably `stretch` will be the most useful override. + + + + + +## Overflowing the containing block + +A common use case for anchor positioning is adding a popover to a word in text. +In these situations, you don't have a way to know where on the screen the word +will appear, or by extension where the anchored element will appear. While you +could use `position-try-options` to specify what happens when the anchored +element overflows, there's a good chance you won't have to. + + + + + +You may have noticed that the label stays within its containing block, even if +that means that it is no longer positioned right at the anchor's center. This is +the default behavior for absolutely positioned elements. + + + + + +In some cases, there isn't a compelling reason that the label can't overflow its +containing block. On this page, the label is small, and the containing block has +healthy margins (except on small screens). In this case, we could specify that +we want `unsafe` alignment. + + + + + +You may think that `safe` is the opposite of `unsafe`, but that's not quite the +case. `safe` alignment is only safe on the start-side, meaning this demo +overflows on the right side, but doesn't on the left side. + + + + + +So: +- unspecified stops overflow on both sides +- `safe` stops overflow only on the start side +- `unsafe` allows overflow on both sides + +I initially found this confusing, as specifying `safe` may make it less safe +depending on the situation. In this example, the area specified by `position-area` +includes the `block-end`, so the implicit `justify-self` value is `start`. By +specifying `safe start` instead, the label overflows on the end side. Remove +`safe` to see the difference. + + + + + +You'll also note that the label text wraps to try to stay inside the containing +block. This is because there is still vertical space in the containing block in +this instance. You can disable this behavior by setting `min-inline-size: +max-content`. + +In the context of anchor positioned elements, where overflow can easily happen +on either side, the `safe` keyword doesn't quite make sense. However, when we +think of it for normal text, this is the behavior that we often expect. For +instance, in the "CSS is awesome" meme, we want text to overflow on the end, but +not at the start. + + + + + +## Future improvements + +While `safe` and `unsafe` behavior has been part of grid and flex layouts for +quite some time, I'm guessing many authors (including me) will encounter it for +the first time (or in new situations) while using anchor positioning. I expect +with more use cases, CSS will make improvements to the capabilities of overflow +alignment. + +Currently, you can't specify an overflow alignment keyword without also +specifying the alignment. I also think it would be useful to add a keyword for +the default behavior, so it could be set like `safe` and `unsafe`, and +potentially add a keyword like `safe-end` that would overflow on the start, but +not the end. diff --git a/src/images/blog/2026/anchor-overflow.jpg b/src/images/blog/2026/anchor-overflow.jpg new file mode 100644 index 000000000..d4953a4db Binary files /dev/null and b/src/images/blog/2026/anchor-overflow.jpg differ diff --git a/src/scss/components/_index.scss b/src/scss/components/_index.scss index 1bd55ce0d..f958810e6 100644 --- a/src/scss/components/_index.scss +++ b/src/scss/components/_index.scss @@ -15,6 +15,7 @@ @forward 'oddnews'; @forward 'events'; @forward 'mentions'; +@forward 'inline-demo'; // Less used, load later @forward 'charts'; diff --git a/src/scss/components/_inline-demo.scss b/src/scss/components/_inline-demo.scss new file mode 100644 index 000000000..c8beec04e --- /dev/null +++ b/src/scss/components/_inline-demo.scss @@ -0,0 +1,28 @@ +/* stylelint-disable hue-degree-notation */ + +/* See https://github.com/stylelint/stylelint/issues/8983 */ + +inline-demo { + border: medium solid var(--text); + position: relative; + margin-block: var(--gutter); + + --code-stripe-1: oklch(from var(--highlight) 0.99 0.1 h); + --code-stripe-2: oklch(from var(--highlight) 0.97 0.1 h); + + &::part(editable-style) { + display: block; + white-space: pre; + font-family: monospace; + font-size: var(--code); + padding: var(--shim); + color: black; + background: repeating-linear-gradient( + 45deg, + var(--code-stripe-1), + var(--code-stripe-1) 10px, + var(--code-stripe-2) 10px, + var(--code-stripe-2) 20px + ); + } +}