Skip to content

Commit

Permalink
[css-anchor-position-1] Add 'inset-area' property. #9145
Browse files Browse the repository at this point in the history
  • Loading branch information
tabatkins committed Nov 9, 2023
1 parent 05c7c9f commit 471d90f
Show file tree
Hide file tree
Showing 2 changed files with 222 additions and 15 deletions.
237 changes: 222 additions & 15 deletions css-anchor-position-1/Overview.bs
Original file line number Diff line number Diff line change
Expand Up @@ -347,12 +347,219 @@ Anchor-Based Positioning {#positioning}
========================

An [=absolutely-positioned=] element
can use the <dfn>anchor()</dfn> function
in its [=inset properties=]
to refer to the position of one or more [=anchor elements=].
The ''anchor()'' function resolves to a <<length>>,
exactly what is needed to position the given inset edge
to the specified position on the [=anchor element=].
can position itself relative to one or more [=anchor elements=] on the page.

The 'inset-area' function offers a convenient grid-based concept
for positioning relative to the [=default anchor element=];
for more complex positioning or positioning relative to multiple elements,
the ''anchor()'' function can be used in the [=inset properties=]
to explicitly refer to edges of an [=anchor element=].

The 'inset-area' Property {#inset-area}
---------------------------------------

<pre class=propdef>
Name: inset-area
Value: none | <inset-area-span> [ / <inset-area-span> ]?
Initial: none
Inherited: no
Applies to: positioned elements with a [=default anchor element=]
Animation type: TBD
</pre>

<pre class=prod>
<dfn>&lt;inset-area-span></dfn> =
[ top || bottom || center ] |
[ left || right || center ] |
[ x-start || x-end || center ] |
[ y-start || y-end || center ] |
[ start || end || center ] |
[ self-start || self-end || center ] |
all
</pre>

Most common use-cases of anchor positioning
only need to worry about
the edges of the positioned element's [=containing block=],
and the edges of the [=default anchor element=].
These lines can be thought of as defining a 3x3 grid;
'inset-area' lets you easily set up the positioned element's [=inset properties=]
by specifying what area of this [=inset-area grid=] you want the positioned element to be in.
Its syntax is:

<dl dfn-for=inset-area dfn-type=value>
: <dfn>none</dfn>
:: The property has no effect.

: <dfn><<inset-area-span>></dfn>
:: Behaves as <css>&lt;inset-area-span> / all</css>,
filling the entire row/column of the grid
indicated by the specified value.

: <dfn><<inset-area-span>> [ / <<inset-area-span>> ]?</dfn>
::
If the element does not have a [=default anchor element=],
or is not an [=absolutely-positioned=] element,
this value has no effect.

Otherwise, the two spans define a rectangular region
of the [=inset-area grid=],
and have the following effects:

1. Any ''top/auto'' [=inset properties=] compute to
the appropriate value
to match the rectangular region.
2. The ''align-self/normal'' value for the [=self-alignment properties=]
behaves as either ''align-self/start'', ''align-self/end'',
or ''align-self/anchor-center'',
depending on the positioning of the region,
to give a good default alignment for the positioned element.

See [[#resolving-spans]] for details on both of these effects.
If the two <<inset-area-span>>s do not define a valid region,
this property is invalid.
</dl>


<h3 id=resolving-spans>
Resolving <<inset-area-span>>s</h3>

The <dfn export>inset-area grid</dfn> is conceptually a 3x3 grid,
composed of four grid lines in each axis.
In order:

* the start edge of the element's [=containing block=]
(aka the position referred to by ''top: 0px;''
or whatever [=inset property=] corresponds to
the start side fo the containing block)
* the ''anchor(start)'' edge of the [=default anchor element=]
* the ''anchor(end)'' edge of the [=default anchor element=]
* the end edge of the element's [=containing block=]
(aka the position referred to by ''bottom: 0px'',
or whatever [=inset property=] is opposite the first one)

Each <<inset-area-span>> specifies 1-3 regions in a given axis of that grid:
the "start" region between the first two of those grid lines;
the "center" region between the center two;
or the "end region" between the last two.

<dl dfn-type=value dfn-for="inset-area, <inset-area-span>">
: <dfn>all</dfn>
:: All three regions of that axis,
spanning the entire breadth of the containing block.

: <dfn>start</dfn>
: <dfn>end</dfn>
: <dfn>self-start</dfn>
: <dfn>self-end</dfn>
: <dfn>center</dfn>
: <dfn>top</dfn>
: <dfn>bottom</dfn>
: <dfn>y-start</dfn>
: <dfn>y-end</dfn>
: <dfn>left</dfn>
: <dfn>right</dfn>
: <dfn>x-start</dfn>
: <dfn>x-end</dfn>
:: Any single keyword refers just to that region in the axis.

Like in ''anchor()'',
''inset-area/start'' and ''inset-area/end''
refer to the writing mode of the element's [=containing block=],
while ''inset-area/self-start'' and ''inset-area/self-end''
refer to the element's own writing mode.

: two keywords
:: Refers to the area spanned by the two indicated regions.

(For example, ''top center'' spans the first two regions,
but ''top bottom'' spans all three.)

: three keywords
:: Refers to all three regions in the axis,
identical to ''inset-area/all''
</dl>

Two spans referring to different axises
thus define a rectangular region of the [=inset-area grid=].

To determine the axises of two spans:

* If a span include a keyword that implies a physical axis
(''inset-area/top'', ''inset-area/x-start'', etc),
that's its axis.
* If both of the spans include a physical keyword,
they must refer to different axises.
If not, then the two spans do not define a valid region.
* If one of the spans include a physical keyword,
and the other doesn't
(it only includes ambiguous keywords,
like ''inset-area/center'' or ''inset-area/start''),
then the other span's axis is perpendicular to the physical one.
* If neither span includes a physical keyword,
the first refers to the [=block axis=]
of the [=containing block=],
and the second to the [=inline axis=].

If the spans define a valid region,
they cause ''top/auto'' values for the [=inset properties=]
to compute to values that will align the [=inset-modified containing block=]
with the boundary of the defined region
on that side.

Each span also implies a default alignment,
which will be used if the [=self-alignment property=] on the element
is ''align-self/normal'':

* If the span includes the center region,
the default alignment in that axis is ''align-self/anchor-center''.
* Otherwise, it's the opposite of the region it specifies:
if it's specifying the "start" region,
the default alignment in that axis is ''align-self/end''; etc.

<div class=example>
For example, assuming an English-equivalent writing mode (horizontal-tb, ltr),
then the spans ''start center / top'' resolve to
the "start" region of the vertical axis,
and the "start" and "center" regions of the horizontal axis,
which will compute the [=inset properties=] to:

<pre highlight=css>
/* "auto" computes to: */
top: 0px;
bottom: anchor(start);
left: 0px;
right: anchor(end);
/* "normal" behaves as: */
align-self: end;
justify-self: anchor-center;
</pre>

In other words, its [=inset-modified containing block=]
will be the pink region in the below diagram,
and the positioned element
will be centered against the top edge of the anchor.

<figure>
<img src="images/inset-area-example.png" width=400>
<figcaption>
An example of ''inset-area: start center / top'' positioning.
</figcaption>
</div>

Note: While the [=default anchor element=] can actually be positioned
outside of the positioned element's [=containing block=],
for the purpose of 'inset-area'&apos;s effects
it's considered to be within the block,
so the grid lines always have the described order.
That is, even if the anchor is entirely below the containing block,
a ''inset-area/bottom'' span will still cause the element to behave as
''top: anchor(end); bottom: 0px; align-content: start;'';
the rules for handling over-constrained [=inset properties=]
will resolve the contradiction.




The ''anchor()'' Function {#anchor-pos}
---------------------------------------------------
Expand Down Expand Up @@ -415,7 +622,7 @@ The ''anchor()'' function has three arguments:

Note: These are only usable in the [=inset properties=]
in the matching axis.
For example, ''left'' is usable in 'left', 'right',
For example, ''anchor()/left'' is usable in 'left', 'right',
or the logical [=inset properties=] that refer to the horizontal axis.

: <dfn>start</dfn>
Expand All @@ -426,18 +633,18 @@ The ''anchor()'' function has three arguments:
in the same axis as the [=inset property=] it's used in,
by resolving the keyword against the [=writing mode=]
of either the positioned element
(for ''self-start'' and ''self-end'')
(for ''anchor()/self-start'' and ''anchor()/self-end'')
or the positioned element's containing block
(for ''start'' and ''end'').
(for ''anchor()/start'' and ''anchor()/end'').

: <dfn><<percentage>></dfn>
: <dfn>center</dfn>
:: Refers to a position
a corresponding percentage between the ''start'' and ''end'' sides,
with ''0%'' being equivalent to ''start''
and ''100%'' being equivalent to ''end''.
a corresponding percentage between the ''anchor()/start'' and ''anchor()/end'' sides,
with ''0%'' being equivalent to ''anchor()/start''
and ''100%'' being equivalent to ''anchor()/end''.

''center'' is equivalent to ''50%''.
''anchor()/center'' is equivalent to ''50%''.

* the optional <<length-percentage>> final argument is a fallback value,
specifying what the function should resolve to
Expand Down Expand Up @@ -687,7 +894,7 @@ for non-''justify-self/auto'' alignment values.

If the element is not [=absolutely positioned=],
or does not have a [=default anchor element=],
this value behaves as ''center''
this value behaves as ''<self-position>/center''
and has no additional effect on how [=inset properties=] resolve.

Issue: Do we want to hook the "try to stay in the IMCB" behavior to safe vs unsafe?
Expand Down Expand Up @@ -784,7 +991,7 @@ only if all the following conditions are true:
on an [=absolutely-positioned=] element.
* If its <<anchor-side>> specifies a physical keyword,
it's being used in an [=inset property=] in that axis.
(For example, ''left'' can only be used in 'left', 'right',
(For example, ''anchor()/left'' can only be used in 'left', 'right',
or a logical [=inset property=] in the horizontal axis.)
* The result of determining the [=target anchor element=] is not nothing when
given the querying element as the element it's used on,
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 471d90f

Please sign in to comment.