1. 소개
CSS 절대 위치 지정은 작성자가 박스를 페이지 어디든지 배치할 수 있게 해주며, 다른 박스의 레이아웃과 상관없이 오직 자신의 포함 블록만을 고려합니다. 이러한 유연성은 매우 유용할 수 있지만, 동시에 제약이 따르기도 합니다—종종 다른 박스를 기준으로 위치를 지정하고 싶을 때가 있습니다. 앵커 위치 지정 (position-anchor 및 position-area 속성, 또는 앵커 함수 anchor(), anchor-size() 활용) 를 통해 작성자는 절대 위치 박스를 페이지의 하나 이상의 다른 박스(그 앵커 참조)에 “앵커링”할 수 있습니다. 동시에 여러 가지 위치를 시도하여 겹침이나 오버플로우를 피하는 “최적”의 위치를 찾을 수도 있습니다.
.anchor{ anchor-name : --tooltip; } .tooltip{ /* Fixpos는 포함 블록 관계를 걱정할 필요가 없다는 의미입니다. 툴팁은 DOM 어디서든 존재할 수 있습니다. */ position: fixed; /* 모든 앵커링 동작은 기본적으로 --tooltip 앵커를 참조하게 됩니다. */ position-anchor: --tooltip; /* 툴팁의 하단이 앵커 상단에 정렬되도록 합니다. 이는 또한 가로 쓰기 모드에서 툴팁과 앵커가 수평 중앙 정렬되는 것도 기본 설정입니다. */ position-area: block-start; /* 만약 툴팁이 윈도우를 넘치면 자동으로 전환해서 툴팁의 상단이 앵커의 하단에 정렬되도록 합니다. */ position-try: flip-block; /* 너무 넓어지는 것을 방지 */ max-inline-size:20 em ; }
Popover API 를 사용하면 position이 자동으로 설정되고 앵커링 관계가 생성됩니다. (anchor-name이나 position-anchor 값을 따로 지정하지 않아도 됨. 암시적 앵커 요소가 정의됩니다.) 따라서 이러한 속성들은 명시적으로 다시 지정할 필요가 없습니다. 올바른 마크업을 사용하면, 이 예제는 다음과 같이 간단해집니다:
.tooltip{ /* popover + popovertarget 속성을 사용하면 'position: fixed'가 설정되고 필요한 position-anchor 관계가 이미 만들어집니다. */ position-area: block-start; position-try : flip-block; max-inline-size : 20 em ; }
1.1. 값 정의
이 명세서는 CSS 속성 정의 관례를 [CSS2]에서 따르며, 값 정의 문법을 [CSS-VALUES-3]에서 사용합니다. 이 명세서에서 정의되지 않은 값 타입은 CSS 값 및 단위 [CSS-VALUES-3]에 정의되어 있습니다. 다른 CSS 모듈과 조합하면 값 타입의 정의가 확장될 수 있습니다.
각 속성 정의에 나열된 속성별 값 외에도, 이 명세서에서 정의된 모든 속성은 CSS 전역 키워드를 속성 값으로 허용합니다. 가독성을 위해 별도로 반복적으로 적지 않았습니다.
선택자 매칭을 제외한 대부분의 CSS 동작과 마찬가지로, 이 명세서에 나오는 기능은 플랫(flat) 요소 트리에 적용됩니다.
2. 앵커 결정
이 명세서의 여러 기능은 앵커 박스의 위치와 크기를 참조합니다. 별도의 명시가 없는 경우, 이는 해당 border box 가장자리와, 관련 주요 박스 및 관련 앵커 요소를 의미합니다. 대부분의 경우 관련 앵커 요소는 기본 앵커 요소로 지정되며, position-anchor 속성을 통해 지정할 수 있습니다. 이는 호스트 언어에서 정의한 암시적 앵커 요소이거나, CSS anchor-name 및 anchor-scope 속성으로 이름이 지정된 앵커일 수 있습니다. (anchor() 함수로도 이름이 지정된 앵커를 직접 참조할 수 있습니다.)
앵커 박스의 위치와 크기는 레이아웃 이후에 결정됩니다. 이 위치와 크기에는 zoom 및 position 기반의 조정 (position: relative 또는 position: sticky 등)과 변형(transform, offset-path 등)이 포함됩니다. 이 경우, 관련 절대 위치 요소의 포함 블록 좌표계에서 앵커 박스의 축정렬 경계 사각형(axis-aligned bounding rectangle)이 사용됩니다. 변형은 종종 별도의 스레드에서 최적화되므로, 앵커 박스의 위치에 대한 변형 기반 갱신은 몇 프레임 지연될 수 있습니다. 실질적으로 가능하다면, 작성자는 대신 절대 또는 상대 위치를 사용하여 이 지연을 피할 수 있습니다.
앵커 박스가 분할(fragmented)된 경우, 해당 포함 블록이 절대 위치 박스의 관련 앵커 박스 외부인 경우, 박스 분할(box fragments)의 축정렬 경계 사각형이 대신 사용됩니다. (절대 위치 박스가 분할 컨텍스트(fragmentation context) 내부에 있으면 앵커 박스를 비분할로 간주하며, 해당 분할 컨텍스트에 의해 스스로도 분할될 수 있습니다.)
성능상의 이유로, 스크롤은 특별하게 처리되며, § 3.3 스크롤 반영을 참고하세요. 기타 레이아웃 후 효과(예: 필터)는 앵커 박스 위치에 영향을 주지 않습니다.
2.1. 앵커 생성: anchor-name 속성
| 이름: | anchor-name |
|---|---|
| 값: | none | <dashed-ident># |
| 초깃값: | none |
| 적용 대상: | 주요 박스(principal box)를 생성하는 모든 요소 |
| 상속 여부: | 아니오 |
| 백분율: | 해당 없음 |
| 계산값: | 지정 값 그대로 |
| 정식 순서: | 문법에 따름 |
| 애니메이션 유형: | 불연속 |
anchor-name 속성은 요소를 앵커 요소로 선언하며, 해당 요소의 주요 박스를 앵커 박스로 사용합니다. 그리고 지정될 앵커 이름 목록을 부여합니다. 값은 다음과 같이 정의됩니다:
- none
-
이 속성은 아무런 효과가 없습니다.
- <dashed-ident>#
-
해당 요소가 주요 박스를 생성하는 경우, 그 요소는 앵커 요소가 되며, 명세된 대로 앵커 이름 목록을 갖게 됩니다. 각 앵커 이름은 loosely matched tree-scoped name입니다.
그 외의 경우, 이 속성은 아무런 효과가 없습니다.
앵커 이름은 고유할 필요가 없습니다. 모든 요소가 지정된 박스의 대상 앵커 요소가 될 수 있는 것은 아닙니다. 따라서 이름의 사용 범위가 적절히 한정된다면, 동일한 이름을 여러 곳에서 재사용할 수 있습니다.
참고: 여러 요소가 동일한 앵커 이름을 공유하고, 모두 특정 위치 지정 박스에 나타나 있다면, 대상 앵커 요소는 DOM 순서에서 마지막 요소가 됩니다. anchor-scope 속성으로 특정 참조 박스에 보이는 이름을 더 한정할 수 있습니다.
앵커 이름은 기본적으로 컨테인먼트에 의해 범위가 제한되지 않습니다. 요소가 스타일이나 레이아웃 컨테인먼트 (또는 이와 유사한 형태의 컨테인먼트)를 갖더라도, 그 자식 요소의 앵커 이름은 페이지의 다른 요소에서 볼 수 있습니다.
참고: 어떤 요소가 다른 요소의 생략된 콘텐츠 안에 있을 때 (예: content-visibility: hidden 등으로 인해), 그 요소는 허용 가능한 앵커 요소가 아니게 되며, 사실상 이름이 없는 것처럼 동작합니다.
참고: 섀도우 트리 안의 위치 지정 요소는 상위 트리에 정의된 앵커 이름을 참조할 수 있습니다. 현재로선, 하위 섀도우 트리에 정의된 앵커 이름은 참조할 수 없습니다.
2.2. 앵커 이름 범위 지정: anchor-scope 속성
| 이름: | anchor-scope |
|---|---|
| 값: | none | all | <dashed-ident># |
| 초깃값: | none |
| 적용 대상: | 모든 요소 |
| 상속 여부: | 아니오 |
| 백분율: | 해당 없음 |
| 계산값: | 지정 값 그대로 |
| 정식 순서: | 문법에 따름 |
| 애니메이션 유형: | 불연속 |
이 속성은 지정된 앵커 이름과 해당 앵커 이름에 대한 조회 범위를 이 요소의 하위 트리로 한정합니다. § 2 앵커 결정을 참조하세요.
값은 다음 의미를 가집니다:
- none
- 앵커 이름 범위에 변경 없음.
- all
-
이 값은 이 요소 또는 자손이 정의하는 모든 앵커
이름
(자손이 anchor-scope로 이미 제한되지 않은 것)의 범위를 이 요소의 자손에만 한정하며,
자손은 이 하위 트리 내의 앵커 요소의
앵커 이름만 참조할 수 있게 제한합니다.
이 값은 같은 트리 범위 내의 앵커 이름에만 영향을 주며, 이는 엄격 매칭(strictly matched) 트리 범위 이름과 같습니다. (anchor-scope: all은 anchor-scope: --foo, --bar, ...처럼 모든 관련 앵커 이름을 나열하는 것과 동일하게 동작합니다.)
- <dashed-ident>
-
이 값은 이 요소 또는 자손이 정의하는 일치하는 앵커
이름
(자손이 anchor-scope로 이미 제한되지 않은 것)의 범위를 이 요소 하위 트리에만 한정시키고,
자손 역시 이 하위 트리 내의 앵커 요소의
해당 앵커 이름만 참조할 수 있게 제한합니다.
<dashed-ident>는 엄격 매칭(strictly matched) 트리 범위 이름을 의미하며, 즉 같은 섀도우 트리 내 앵커 이름에만 매칭될 수 있습니다.[CSS-SCOPING-1]
이 속성은 암시적 앵커 요소에는 영향을 주지 않습니다.
li{ anchor-name : --list-item; anchor-scope : --list-item; } li .positioned{ position : absolute; position-anchor : --list-item; position-area : inline-start; }
anchor-scope가 없다면,
모든
li
요소가 모든 위치 지정된 요소에 보이게 되어,
모든 요소가 마지막
li
기준으로 쌓이게 됩니다.
2.3. 앵커 찾기
이 명세서의 여러 기능은 앵커 지정자를 받아 대상 앵커 요소를 찾습니다. 앵커 지정자는 <dashed-ident> (그리고 트리 범위 참조(tree-scoped reference)) 로, 페이지 내 다른 곳에 있는 anchor-name 값과 일치시켜야 하거나, 혹은 키워드 auto이거나, 아무것도 없는(지정자 누락) 경우도 있습니다.
참고: 일반적으로 이 조건이 포괄하는 규칙은, 요소는 해당 위치 지정 박스가 참조하려는 요소 박스가 완전히 레이아웃된 이후에만 대상 앵커 요소가 될 수 있다는 것입니다. CSS의 레이아웃 규칙은, 앵커와 위치 지정 박스의 관계 및 포함 블록에 따라 이에 대한 유용한 보증을 제공합니다. 아래 조건 목록은 쌓기 컨텍스트(stacking context) 규칙을 이 목적에 맞게 재정의한 것으로, 앵커 위치 지정에서 순환성이 발생하지 않도록 보장합니다.
-
anchor spec이 전달되지 않은 경우, 기본 앵커 요소가 존재하면 반환하고, 그렇지 않으면 아무것도 반환하지 않습니다.
-
anchor spec이 auto라면:
-
query el이 암시적 앵커 요소를 가지고 있으며, 그것이 허용 가능한 앵커 요소라면, 해당 요소를 반환합니다.
-
그 외에는 아무것도 반환하지 않습니다.
참고: 향후 API에서도 암시적 앵커 요소가 정의될 수 있으며, 그럴 경우 이 알고리즘에서 명확하게 다루어 일관성을 보장하게 됩니다.
-
-
그 외의 경우, anchor spec은 <dashed-ident>입니다. 다음 조건을 만족하는 마지막 요소 el을 트리 순서대로 반환합니다:
-
el이 허용 가능한 앵커 요소일 것 (query el에 대해).
조건을 만족하는 요소가 없으면, 아무것도 반환하지 않습니다.
참고: anchor-scope는 특정 앵커 이름의 가시성을 제한할 수 있으며, 이는 어떤 요소가 주어진 조회에 앵커 요소가 될 수 있는지에 영향을 줍니다.
참고: 한 anchor-name이 특정 섀도우 트리의 스타일로 정의되어 있더라도, 앵커 함수가 다른 섀도우 트리 스타일에 있을 경우 보이지 않게 되어, 캡슐화가 유지됩니다. 하지만 요소는 서로 다른 섀도우 트리 간에도 앵커 지정이 가능한데, anchor-name과 앵커 함수가 같은 트리 내의 스타일에서 오는 경우에만 가능합니다. 예를 들어 ::part()를 통해 섀도우 안의 요소를 스타일링 할 때 등입니다. (암시적 앵커 요소 역시 본질적으로 단일 트리로 제한되지 않지만, 해당 동작의 자세한 내용은 API 구현에 따라 달라집니다. )
-
possible anchor는 요소이거나, 완전히 스타일 지정 가능한 트리 준수(tree-abiding) 가상 요소(pseudo-element)여야 합니다.
-
possible anchor는 anchor-scope의 효과에 따라 possible anchor 또는 그 조상에 의해 positioned el 기준으로 범위 내에 있어야 합니다.
-
possible anchor가 positioned el보다 엄밀히 앞서 레이아웃되어야 하며, 즉 다음 중 하나여야 합니다:
-
possible anchor와 positioned el이 동일한 원래 포함 블록을 가지며, 아래 둘 중 하나:
-
possible anchor가 더 낮은 top layer에 있을 것,
-
두 요소가 같은 top layer에 있지만 possible anchor가 절대 위치가 아니거나, 플랫 트리(flat tree) 순서상 더 먼저 나올 것
-
-
possible anchor의 포함 블록을 생성하는 요소(존재하는 경우)가 positioned el의 허용 가능한 앵커 요소일 것
-
-
possible anchor가 다른 요소의 생략된 콘텐츠(skipped contents) 안에 있다면, positioned el도 반드시 같은 요소의 생략된 콘텐츠 안에 있어야 합니다.
참고: 즉, positioned el과 possible anchor가 같은 생략 "leaf" 안에 있으면 앵커링이 가능하지만, leaf를 "건너뛰는" 것처럼 앵커링할 수 없습니다. 즉, 둘을 포함한 상위 요소가 생략 처리되어도 positioned el이 앵커를 다른 곳으로 옮기지는 않지만, 페이지의 다른 위치 지정 요소가 해당 생략된 요소에 앵커링하는 것은 방지하게 됩니다.
2.4. 기본 앵커: position-anchor 속성
| 이름: | position-anchor |
|---|---|
| 값: | none | auto | <anchor-name> |
| 초깃값: | none |
| 적용 대상: | 절대 위치 박스 |
| 상속 여부: | 아니오 |
| 백분율: | 해당 없음 |
| 계산값: | 지정 값 그대로 |
| 정식 순서: | 문법에 따름 |
| 애니메이션 유형: | 불연속 |
position-anchor 속성은 기본 앵커 요소를 지정하며, 이는 position-area, position-try, 그리고 (기본적으로) 이 요소에 적용된 모든 앵커 함수에서 사용됩니다. position-anchor는 reset-only 하위 속성이며, position의 일부입니다.
- none
-
박스에 기본 앵커 요소가 없습니다.
- auto
- <anchor-name>
-
지정된 대상 앵커 요소가 <anchor-name>에 의해 선택되어 이 박스의 기본 앵커 요소가 됩니다.
초기 값을 좀 더 매직하게, none과 auto 중에서 position-area의 사용 여부에 따라 자동 선택되도록 변경할 수도 있습니다. [이슈 #13067]
주요 박스는 기본 앵커 요소의 박스이며, 이 박스가 기본 앵커 박스가 됩니다.
.anchored{ position : absolute; top : calc ( .5 em +anchor ( outside)); /* 앵커 이름이 지정되지 않았으므로, 자동으로 기본 앵커 박스를 참조합니다. */ } .foo.anchored{ position-anchor : --foo; } .bar.anchored{ position-anchor : --bar; }
2.4.1. 암시적 앵커 요소
몇몇 명세는 특정 상황에서 특정 요소가 다른 요소의 암시적 앵커 요소임을 정의할 수 있습니다.
TODO: HTML 명세에 popover 관련 세부 사항이 확정되면, 해당 예시로 채우세요.
암시적 앵커 요소는 auto 키워드로 position-anchor에서 참조하거나, 앵커 함수에서 앵커 참조를 생략하여 참조할 수 있습니다.
암시적 앵커 요소가 가상 요소(pseudo-element)인 경우, 별도 명시가 없다면 그 원본 요소(originating element)가 됩니다.
2.5. 앵커 관련성
요소 el이 사용자에게 관련이 있는지 판단할 때, el의 자손이 위치 지정 박스의 대상 앵커 요소인 경우 (해당 박스 자체는 생략(skipped)되지 않았고, 그 포함 블록이 el 또는 el의 자손이 아닌 경우), el은 사용자에게 관련이 있다고 간주해야 합니다.
참고: 예를 들어, content-visibility: auto 하위 트리에서의 앵커는 그 트리를 사용하는 위치 지정 박스가 skipped되지 않은 한, 콘텐츠 생략이 일어나지 않도록 하게 됩니다. (단, 앵커와 위치 지정 박스 모두 동일한 content-visibility: auto 요소 하위에 있으면 서로 순환적으로 서로를 계속 보이게 하지 않습니다.)
3. 앵커 기반 위치 지정
절대 위치 박스는 페이지 내 여러 앵커 박스를 기준으로 위치를 잡을 수 있습니다.
position-area 속성은 기본 앵커 박스를 기준으로 한 격자(grid) 기반 위치 지정 개념을 쉽게 제공하며, 더 복잡하거나 여러 박스를 기준으로 한 위치 지정에는 anchor() 함수를 inset 속성에서 활용해 특정 앵커 박스의 변(edge)을 명시적으로 참조할 수 있습니다.
3.1. position-area 속성
| 이름: | position-area |
|---|---|
| 값: | none | <position-area> |
| 초깃값: | none |
| 적용 대상: | 기본 앵커 박스가 있는 위치 지정 박스 |
| 상속 여부: | 아니오 |
| 백분율: | 해당 없음 |
| 계산값: | 키워드 none 또는 키워드 쌍, § 3.1.3 <position-area>의 계산 값 및 직렬화 참고 |
| 정식 순서: | 문법에 따름 |
| 애니메이션 유형: | TBD |
앵커 위치 지정의 대부분의 일반적인 사용 사례는, 위치 지정된 박스의 포함 블록의 변과 기본 앵커 박스의 변만을 고려합니다. 이러한 선들은 3×3 그리드를 정의하는 것으로 볼 수 있으며, position-area로 이 position-area 그리드의 어떤 영역에 위치시킬지 쉽게 지정할 수 있습니다.
- none
-
이 속성은 아무런 효과가 없습니다.
- <position-area>
-
박스에 기본 앵커 박스가 없거나, 절대 위치 박스가 아닌 경우, 이 값은 효과가 없습니다.
그 외에는, position-area 그리드의 영역을 선택하며, 해당 영역이 이 박스의 포함 블록이 됩니다.
참고: 즉, inset 속성 들은 position-area로부터의 오프셋을 지정하게 되며, max-height: 100%같은 일부 속성 값도 position-area 기준이 됩니다.
none이 아닌 값은 다음 추가 효과를 가집니다:
-
스크롤 가능 포함 블록이 로컬 포함 블록 대신 사용됩니다. absolute-position 포함 블록이 스크롤 컨테이너에 의해 생성될 때 전체 스크롤 가능 오버플로 영역이 (대부분) 위치 지정에 제공되게 됩니다.
-
normal 값이 자기 정렬(self-alignment) 속성에서 대응되는 값으로 변환됩니다. § 4.1 영역별 기본 정렬 참고.
3.1.1. Position Area Grid 해석
position-area 그리드는 3×3 그리드이며, 각 축에 4개의 그리드 선이 있습니다. 순서는 (쓰기 모드를 기준으로 포함 블록의):
참고: 기본 앵커 박스가 수정 전 포함 블록의 일부 또는 전체 바깥에 있으면, position-area 그리드의 일부 행/열 크기가 0이 될 수 있습니다.
3.1.2. <position-area> 값의 문법
위치는 값 쌍으로 지정하며, 플로우 기준 또는 물리적 용어로 표현할 수 있습니다. <position-area> 값의 허용 문법은 다음과 같습니다:
<position-area> = [
[ left | center | right | span-left | span-right
| x-start | x-end | span-x-start | span-x-end
| self-x-start | self-x-end | span-self-x-start | span-self-x-end
| span-all ]
||
[ top | center | bottom | span-top | span-bottom
| y-start | y-end | span-y-start | span-y-end
| self-y-start | self-y-end | span-self-y-start | span-self-y-end
| span-all ]
|
[ block-start | center | block-end | span-block-start | span-block-end | span-all ]
||
[ inline-start | center | inline-end | span-inline-start | span-inline-end
| span-all ]
|
[ self-block-start | center | self-block-end | span-self-block-start
| span-self-block-end | span-all ]
||
[ self-inline-start | center | self-inline-end | span-self-inline-start
| span-self-inline-end | span-all ]
|
[ start | center | end | span-start | span-end | span-all ]{1,2}
|
[ self-start | center | self-end | span-self-start | span-self-end | span-all ]{1,2}
]
<position-area> 값은 position-area 그리드의 영역을 선택하며, 해당 영역이 차지하는 행과 열을 다음과 같이 지정합니다:
- start, end, self-start, self-end
- top, bottom, left, right
- y-start, y-end, self-y-start, self-y-end
- x-start, x-end, self-x-start, self-x-end
- block-start, block-end, self-block-start, self-block-end
- inline-start, inline-end, self-inline-start, self-inline-end
- center
- top, bottom, left, right
-
해당 축의 단일 행 또는 열.
anchor()와 마찬가지로 일반 논리 키워드(start, end 등)는 박스의 쓰기 모드 기준입니다. x-start 등은 지정된 물리 축 기준으로 방향을 결정합니다.
self-* 논리 키워드는 (self-start, self-x-end 등) 동일하지만 박스의 쓰기 모드 기준입니다.
- span-start, span-end, span-self-start, span-self-end
- span-top, span-bottom, span-left, span-right
- span-y-start, span-y-end, span-self-y-start, span-self-y-end
- span-x-start, span-x-end, span-self-x-start, span-self-x-end
- span-block-start, span-block-end, span-self-block-start, span-self-block-end
- span-inline-start, span-inline-end, span-self-inline-start, span-self-inline-end
- span-top, span-bottom, span-left, span-right
-
해당 축의 인접한 두 행 또는 열. 중심 행/열과 단일 키워드에 해당하는 행/열. (예: span-top은 첫 두 행(중심+top)을 포함.)
- span-all
-
해당 축의 모든 3개 행 또는 열.
일부 키워드는 축이 명확하지 않습니다: center, span-all, start 등 block/inline 축을 명확히 지정하지 않은 키워드. 다른 키워드가 축을 명확히 한다면, 모호한 키워드는 반대 축을 가리킵니다. (예: block-start center에서 center는 inline 축.) 둘 다 모호하면, 첫 번째는 박스의 block 축, 두 번째는 inline 축입니다. (예: span-all start는 span-all inline-start와 동일.)
키워드가 하나면, 해당 축이 명확하면 두 번째 키워드는 span-all로 처리; 그렇지 않으면 키워드를 반복해서 사용한 것과 동일하게 동작합니다. (예: top은 top span-all과 같고, center는 center center와 동일.)
3.1.3. <position-area>의 계산값 및 직렬화
계산값은 <position-area> 값에서 각 축에 대해 선택된 트랙을 나타내는 두 키워드이며, 긴 논리(block-start)와 짧은 논리(start) 키워드는 동등하게 처리합니다. 직렬화는 위 문법 순서대로, 논리 키워드는 짧은 형태로 직렬화됩니다 (예: start start 대신 block-start inline-start 대신).
3.2. 앵커 기준 인셋: anchor() 함수
절대 위치 박스는 anchor() 함수를 인셋 속성 값으로 사용해 하나 이상의 앵커 박스의 위치를 참조할 수 있습니다. anchor() 함수는 <length>로 해석됩니다. 이 함수는 inset 속성에서만 허용되며, 그 외의 경우에는 유효하지 않습니다.
| 이름: | top, left, right, bottom |
|---|---|
| 새로운 값: | <anchor()> |
<anchor()> = anchor( <anchor-name>? && <anchor-side>, <length-percentage>? )
<anchor-name> = <dashed-ident>
<anchor-side> = inside | outside
| top | left | right | bottom
| start | end | self-start | self-end
| <percentage> | center
anchor() 함수는 세 가지 인수를 가집니다:
-
<anchor-name> 값은 참조할 앵커 요소를 찾는 방법을 지정합니다. 가능한 값은 다음과 같습니다:
- <dashed-ident>
- 생략됨
-
박스에 정의된 기본 앵커 요소를 선택합니다 (가능하다면).
자세한 내용은 대상 앵커 요소를 참고하십시오.
-
<anchor-side> 값은 대상 앵커 요소의 해당 변 위치를 참조합니다. 가능한 값은 다음과 같습니다:
- inside
- outside
-
앵커 박스의 변 중 하나로 해석되며, 어느 inset 속성에 사용되었는지에 따라 달라집니다. inside는 inset 속성과 같은 방향(변)을 의미하며 (즉, 위치 지정 박스를 앵커 박스의 "안쪽"에 맞춤), outside는 반대쪽을 의미합니다.
- top
- right
- bottom
- left
- right
-
앵커 박스의 해당 변을 참조합니다.
참고: 이 값들은 inset 속성의 동일 축에서만 사용할 수 있습니다. 예를 들어, left는 left, right, 또는 수평 축의 논리 inset 속성에서 사용할 수 있습니다.
- start
- end
- self-start
- self-end
- end
-
해당 축에서 앵커 박스의 한 변을 참조하며, 키워드는 쓰기 모드를 기준으로 해석됩니다. (self-start와 self-end는 위치 지정 박스, start, end는 포함 블록의 쓰기 모드 기준)
- <percentage>
- center
-
해당 변의 start에서 end까지의 일정 퍼센트 위치를 참조합니다. 0%는 start와 같으며, 100%는 end와 같습니다.
center는 50%와 같습니다.
- inside
-
마지막 선택적 <length-percentage> 인수는 폴백 값으로, 해결 불가 anchor 함수일 때 적용될 값을 지정합니다.
anchor() 함수가 해결 가능한 anchor 함수일 때는 계산값 시점에 (스타일 & 레이아웃 인터리빙 사용) 위치 지정 박스의 <length>로 해석되며, 해당 속성에 맞는 inset-modified 포함 블록의 변과 대상 앵커 요소의 앵커 박스의 지정된 변을 맞추기에 필요한 값을 나타냅니다.
참고: 즉, 트랜지션 및 애니메이션이 anchor 함수를 사용하는 속성에서 "예상대로" 동작하게 됩니다: 앵커 박스의 위치가 변하든, 앵커 요소의 추가/삭제 등 anchor-name 속성의 변경 등, 다양한 변화에 모두 동작합니다.
.bar 요소의 block-start 변을
--foo 앵커의 block-start 변에 맞추도록 길이를 해석합니다.
반면에,
.bar { inset-block-end: anchor(--foo block-start); }에서는
.bar 요소의 block-end 변을
--foo 앵커의 block-start 변에 맞추도록 해석됩니다.
inset-block-start와 inset-block-end 값은 각기 다른 변(요소의 포함 블록의 block-start, block-end) 기준 오프셋이므로, 동일한 anchor()도 각각 다른 길이로 해석될 수 있습니다.
더 나은 예시가 필요하며; 이 예시는 anchor-center만으로 쉽게 구현 가능합니다. [이슈 #10776]
예를 들어, 아래는 요소의 inset-modified 포함 블록을 앵커 박스에 중앙 정렬하고 포함 블록을 넘지 않는 최대 너비로 하는 방법입니다:
.centered-message{ position : fixed; max-width : max-content; justify-self : center; --center : anchor ( --x50 % ); --half-distance : min ( abs ( 0 % -var ( --center)), abs ( 100 % -var ( --center)) ); left : calc ( var ( --center) -var ( --half-distance)); right : calc ( var ( --center) -var ( --half-distance)); bottom : anchor ( --x top); }
이 방법은 예를 들어
input
요소의 에러 메시지 표시처럼
해당 입력 필드와의 연관성을 쉽게 파악할 수 있게 할 때 적합할 수 있습니다.
3.2.1. anchor()의 해상도
anchor() 함수는 해결 가능한 anchor 함수 가 되려면 다음 모든 조건을 만족해야 합니다:
-
절대 위치 박스에 적용되어야 합니다.
-
그 <anchor-side>가 물리적 키워드를 지정한다면, 해당 축에 적용되는 인셋 속성에 지정해야 합니다. (예: left는 left, right, 또는 수평축의 논리 인셋 속성에서만 사용할 수 있음.)
-
함수가 사용된 박스와 함수 내에 명시된 <anchor-name>에 대해, 대상 앵커 요소가 존재해야 합니다.
이 중 어느 하나라도 거짓이면, anchor() 함수는 지정된 폴백 값으로 계산됩니다. 폴백 값이 없다면, 이를 참조한 선언은 계산값 시점에서 무효가 됩니다.
3.3. 스크롤 반영
성능 때문에, 구현은 보통 스크롤을 별도의 스크롤/컴포지팅 스레드에서 처리하며, 여기서는 레이아웃 등 무거운 작업이 아니라 단순 이동/변환 등만 처리되어 스크롤 반응이 인간 감각상 '즉각적'으로 느껴질 수 있습니다.
스크롤로 인해 단순히 anchor-positioned 요소가 이동하기만 할 때는 문제 없습니다; 움직임은 스크롤 스레드에서 수행되어 스크롤 콘텐츠와 같이 매끄럽게 움직일 수 있습니다. 하지만 앵커 위치 지정(anchor positioning)은 요소가 자신의 반대쪽 변의 위치를 서로 다른 스크롤 컨텍스트의 요소에 의존하게 할 수 있으므로, 스크롤이 변의 하나만 이동시키고 크기 변화를 유발해 결국 레이아웃이 필요할 수도 있습니다. 이런 경우 스크롤 스레드에서 처리할 수 없습니다!
이를 보완하고 다양한 앵커 지정의 자유도는 최대한 유지하기 위해, 앵커 위치 지정(anchor positioning)은 기억된 스크롤 오프셋과 스크롤 보상 개념을 함께 사용합니다.
-
위치 지정 요소가 처음 화면에 보이거나 폴백이 바뀔 때, 위치는 모든 앵커 참조(anchor reference)의 최신 위치에 따라 올바르게 계산됩니다.
이 앵커 참조(anchor reference)가 서로 다른 스크롤 컨텍스트에 속한다면, 그 총 스크롤 오프셋이 기억되며, 이후 해당 요소가 스크롤되어도 레이아웃은 기억된 오프셋을 계속 사용합니다. (기억되는 것은 스크롤 오프셋 자체뿐이며, 실질적인 레이아웃 위치는 매번 새로 계산되어 정확성을 유지함.) 위치 지정 요소가 더 이상 표시되지 않거나 폴백이 바뀌면 새로 계산합니다.
-
유일한 예외는 기본 앵커 요소입니다; 그 요소가 기억된 스크롤 오프셋에서 벗어나면 위치 지정 요소가 함께 움직입니다. 이것은 *오직* 위치 이동만 반영하므로, 위치 지정 요소의 크기가 변하거나 재레이아웃이 필요한 변화는 일으킬 수 없습니다.
결론적으로 앵커 위치 지정은 어떤 요소에 앵커링하든 대체로 "그냥 동작"하지만, 스크롤에 어떻게 반응할 수 있는지는 일부 제한이 있을 수 있습니다.
요소가 위치 폴백 스타일 결정 시에도 앵커 재계산 지점이 발생하며, 폴백 스타일이 바뀌면 선택된 폴백 스타일에 연관된 앵커 재계산 지점의 결과를 사용합니다.
요소 abspos에 대해 앵커 재계산 지점이 발생할 때마다, abspos의 각 앵커 참조(anchor reference) anchor마다 기억된 스크롤 오프셋 을 할당하는데, 이는 anchor의 모든 스크롤 컨테이너 조상(단, abspos의 포함 블록은 제외)들의 현재 스크롤 오프셋 합계와 같습니다. 기억된 오프셋에는 position: sticky와 같은 다른 스크롤 의존 위치 변동도 반영합니다. abspos에 기본 앵커 요소가 있다면, 실제로 앵커 참조가 없어도 항상 기억된 스크롤 오프셋을 계산합니다.
모든 앵커 참조(anchor reference)는 마치 모든 스크롤 컨테이너가 초기 스크롤 위치에 있다고 가정하여 계산한 후, 연관된 기억된 스크롤 오프셋을 더해 줍니다.
변환(transform)도 스크롤처럼 동일한 문제를 가지므로, 앵커 위치 지정에서도 기본적으로 고려하지 않습니다. 변환의 효과도 여기서 포함시켜도 될지 논의가 필요합니다.
이 방식으로 위치 지정 요소는 자신의 앵커 참조(anchor reference)들의 스크롤 위치에 한 번 반응할 수 있지만, 이들 중 어느 하나라도 스크롤되면 더 이상 해당 요소에 앵커링된 것으로 보이지 않게 됩니다 (단, 스크롤/스레드 외의 움직임에는 계속 반응). 이 문제는 원칙적으로 해결할 수 없지만, 하나의 앵커 참조(anchor reference) 스크롤에는 대응할 수 있습니다. 그 대상은 기본적으로 기본 앵커 요소입니다:
-
abspos에 기본 앵커 박스가 있다.
-
abspos에 앵커 참조(anchor reference)가 있고, 그 대상이 기본 앵커 박스 또는 같은 스크롤 컨텍스트에 있다, 즉 다음 중 적어도 하나를 만족한다:
-
해당 축에서 abspos의 자기 정렬 속성 값이 anchor-center이다;
-
position-area 속성 값이 none이 아니다;
-
at least one anchor() 함수가 해당 축의 used inset 속성에서, 같은 최인접 스크롤 컨테이너를 가지는 대상 앵커 요소를 참조한다.
-
참고: abspos에 position options list가 있다면, 스크롤 보상(compensate for scroll) 여부는 적용된 폴백 스타일에 따라 달라질 수 있습니다.
abspos의 기본 스크롤 시프트(default scroll shift)는 각각의 축(수평, 수직)에 대해 길이 한 쌍으로 표현됩니다. 각 길이는 다음과 같이 계산됩니다:
-
해당 축에서 스크롤 보상(compensate for scroll)을 하면, 길이는 기본 앵커 요소의 기억된 스크롤 오프셋과 현재 이를 다시 계산했을 때의 값 차이입니다.
-
그렇지 않으면 길이는 0입니다.
레이아웃이 완료된 후, abspos는 기본 스크롤 시프트만큼 추가로 이동되며, 이는 마치 변환(transform) 효과가 적용된 것과 같지만 (다른 transform 이전에) 적용됩니다.
스냅샷의 정밀한 시점 정의 필요: 매 프레임마다 업데이트되는지, 스타일 재계산 전인지 등.
기억된 스크롤 오프셋처럼, 기본 앵커 요소의 변환(transform)까지도 반영할 수 있는지 논의가 필요합니다.
참고: 기억된 스크롤 오프셋은 anchor() 함수 값에 영향을 주지만, 기본 스크롤 시프트는 요소 자체를 직접 이동시킵니다 (inset 속성, 정렬 등 적용 후에 이동). 보통은 차이가 없으나, round(anchor(outside), 50px)처럼 앵커 위치에 비선형 변환이 적용되면 동작 차이가 드러날 수 있습니다.
4. 앵커 기반 정렬
4.1. 영역별 기본 정렬
position-area가 none이 아닌 경우, 사용 값이 normal인 self-alignment는 <position-area> 값에 따라 달라지며, 박스가 앵커 쪽으로 정렬되도록 변경됩니다:
-
한 축에서 center 트랙만 선택된 경우, 해당 축의 기본 정렬은 center입니다.
-
세 트랙 모두 선택된 경우, 해당 축의 기본 정렬은 anchor-center입니다.
-
그 외의 경우, 해당 축의 기본 정렬은 명시되지 않은 쪽 트랙 방향으로 됩니다: 만약 축의 “start” 트랙만 명시된 경우, 기본 정렬은 end 등입니다.
하지만 관련 축의 inset 속성 중 하나만 auto이면, 기본 정렬은 auto가 아닌 인셋 쪽 변으로 향하고, 이 정렬은 unsafe 정렬입니다.
Note: 이 단일 auto 동작은 한 인셋값으로 절대 위치 박스의 위치를 제어하던 기존 방식과 호환됩니다.
이 동작은 위치 지정 박스가 예상보다 포함 블록이 작아져도 가능한 한 보이고 의도한 범위를 유지하도록 만들어줍니다.
예를 들어 position-area: bottom span-right 값을 사용하면 위치 지정 박스가 앵커의 왼쪽 변부터 포함 블록의 오른쪽 변까지 늘어나 해당 공간에서 기본적으로 왼쪽 정렬합니다. 하지만 박스가 그 공간보다 더 크면 (예: 앵커가 화면 오른쪽 끝에 매우 가까이 있으면) 박스는 보이도록 왼쪽으로 이동합니다.
4.2. 앵커에 중앙 정렬: anchor-center 정렬 값
| 이름: | justify-self, align-self, justify-items, align-items |
|---|---|
| New values: | anchor-center |
self-alignment 속성은 절대 위치 박스가 inset-modified 포함 블록 내에서 스스로 정렬하게 해줍니다. 기존 값들과 적절한 inset 속성 조합만으로도 대부분의 정렬에는 충분하지만, 앵커 위치 지정에서 자주 쓰이는 "앵커 위에 중앙 정렬"은 복잡한 스타일 설정이 필요했습니다.
새로운 anchor-center 값은 이 경우를 아주 간단하게 만듭니다: 위치 지정 박스에 기본 앵커 박스가 있으면, 해당 축에서 (가능한 한) 기본 앵커 박스 위에 중앙 정렬됩니다. 추가적으로 다음 효과가 있습니다:
-
해당되는 경우 스크롤 가능 포함 블록이, 로컬 포함 블록 대신 사용되어 전체 스크롤 가능 오버플로 영역이 위치 지정에 활용될 수 있습니다.
박스가 절대 위치가 아니거나, 기본 앵커 박스가 없으면, 이 값은 center처럼 동작하며, inset 속성 해석에는 추가 효과가 없습니다.
Note: anchor-center 사용 시 앵커가 박스의 원래 포함 블록 변에 너무 가까우면, 박스가 원래 포함 블록 내에 있도록 가운데 정렬에서 "이동"됩니다. 자세한 내용은 CSS Box Alignment 3 § 4.4 Overflow Alignment: the safe and unsafe keywords and scroll safety limits를 참고하세요.
5. 앵커 기반 크기 조정
절대 위치 박스는 anchor-size() 함수를 크기 속성(sizing properties)에 사용해, 하나 이상의 앵커 박스의 크기를 참조할 수 있습니다. anchor-size() 함수는 <length>로 해석됩니다. 이 함수는 허용된 @position-try 속성에서만 허용되며, 그 외에는 유효하지 않습니다.
5.1. anchor-size() 함수
| 이름: | width, height, min-width, min-height, max-width, max-height, top, left, right, bottom, margin-top, margin-left, margin-right, margin-bottom |
|---|---|
| 새로운 값: | <anchor-size()> |
anchor-size() = anchor-size( [ <anchor-name> || <anchor-size> ]? , <length-percentage>? ) <anchor-size> = width | height | block | inline | self-block | self-inline
anchor-size() 함수는 anchor()와 유사하며, 인수도 동일하나 <anchor-side> 키워드 대신 <anchor-size> 키워드를 사용하여, 대향하는 두 변 사이의 거리를 참조합니다.
물리적 <anchor-size> 키워드 (width 및 height) 는 각각 대상 앵커 요소의 너비/높이를 의미합니다. anchor()와는 달리 축 일치 제한이 없습니다. 예를 들어 width: anchor-size(--foo height); 도 유효합니다.
논리 <anchor-size> 키워드 (block, inline, self-block, self-inline) 는 각 키워드마다 박스 (self-block, self-inline: 해당 박스의 writing mode) 또는 포함 블록(block, inline: 포함 블록의 writing mode) 의 writing mode에 따라 물리적 키워드로 매핑됩니다.
<anchor-size> 키워드가 생략되면, anchor-size()가 사용된 속성의 축에 맞는 키워드로 동작합니다. (예: width: anchor-size()는 width: anchor-size(width)와 동일합니다.)
anchor-size() 함수가 해결 가능한 anchor-size 함수라면, 계산값 시점에 (스타일 및 레이아웃 인터리빙으로) <length>로 해석되며, 이 값은 대상 앵커 요소 앵커 박스의 해당 변 (좌/우 또는 상/하) 사이 거리입니다.
5.1.1. anchor-size()의 해상도
anchor-size() 함수는 해결 가능한 anchor-size 함수가 되려면 다음 조건을 모두 만족해야 합니다:
-
절대 위치 박스에 적용되어야 합니다.
-
함수가 사용된 박스와 함수에 명시된 <anchor-name>에 대해 대상 앵커 요소가 존재해야 합니다.
이 조건 중 하나라도 거짓이면, anchor-size() 함수는 지정된 폴백 값으로 해석됩니다. 폴백 값이 없는 경우, 이를 참조한 선언은 계산값 단계에서 무효가 됩니다.
6. 오버플로우 관리
앵커 위치 지정(anchor positioning)은 강력하지만 예측 불가할 수도 있습니다. 앵커 박스는 페이지 어디에도 위치할 수 있으므로, (예: 앵커 위/오른쪽 등) 특정 방식으로 박스를 위치시키면 위치 지정 박스가 포함 블록을 넘치거나 화면 밖에 일부 배치될 수 있습니다.
이를 완화하기 위해 절대 위치 박스는 position-try-fallbacks 속성을 사용해 (기존 스타일에서 생성된 또는 @position-try 규칙에서 명시된) UA가 위치 지정 후 박스가 넘치면 시도해볼 추가 위치 옵션을 지정할 수 있습니다. 각 옵션은 position-try-order에서 지정된 순서대로 박스에 하나씩 적용되고, 포함 블록을 넘치지 않는 첫 옵션이 채택됩니다.
한 번 옵션이 선택되면, 해당 요소는 다시 넘칠 때까지 그 스타일을 유지하며, 그 전에 넘침 없이 사용 가능한 더 바람직한 옵션이 생겨도 즉시 이전으로 돌아가지 않습니다. (자세한 내용은 마지막 성공 위치 옵션 기억/해제 참고.)
#myPopover{ position : fixed; position-anchor : --button; position-area : bottom span-x-end; position-try-fallbacks : flip-x, flip-y, flip-x flip-y, bottom, top; /* 팝오버는 버튼만큼 최소한 넓습니다 */ min-width:anchor-size ( width); /* 팝오버는 메뉴 항목 2개만큼은 최소한 높습니다 */ min-height:6 em ; }
6.1. 대체 옵션 제공: position-try-fallbacks 속성
| 이름: | position-try-fallbacks |
|---|---|
| 값: | none | [ [<dashed-ident> || <try-tactic>] | <position-area> ]# |
| 초깃값: | none |
| 적용 대상: | 절대 위치 박스 |
| 상속 여부: | 아니오 |
| 백분율: | 해당 없음 |
| 계산값: | 지정 값 그대로 |
| 정식 순서: | 문법에 따름 |
| 애니메이션 유형: | 불연속 |
이 속성은 절대 위치 박스가 inset-modified 포함 블록을 넘칠 때 시도할 대체 위치 스타일 목록을 제공합니다. 이 위치 옵션 리스트(position options list)는 처음에는 요소의 폴백 기본 스타일 즉, computed styles에서 position-try-fallbacks 미적용 상태로 생성된 위치 옵션(position option) 하나만 포함합니다.
리스트의 각 쉼표 단위 항목은 별도의 옵션입니다. @position-try 블록의 이름이거나, 해당 박스의 기존 computed style을 자동 변환하는 <try-tactic>입니다.
값의 의미는 다음과 같습니다:
- none
-
이 속성은 아무런 효과가 없습니다. 박스의 위치 옵션 리스트는 비어 있습니다.
- <dashed-ident>
-
해당 이름의 @position-try 규칙이 있다면, 그 위치 옵션을 위치 옵션 리스트에 추가합니다.
그 외에는 효과가 없습니다.
- <try-tactic>
-
지정된 try-tactic을 실행하여 박스의 기본 스타일을 자동 변환한 결과로 위치 옵션을 생성하고, 해당 위치 옵션을 위치 옵션 리스트에 추가합니다.
<try-tactic> = flip-block || flip-inline || flip-start || flip-x || flip-y
- flip-block
-
블록 축(block axis)의 값을 교체합니다 (예: margin-block-start와 margin-block-end 사이), 본질적으로 인라인 축 기준 선을 따라 미러링합니다.
- flip-inline
- flip-x
-
수평 축의 값을 교체합니다 (예: margin-left와 margin-right 사이), 본질적으로 수직 축 기준 선을 따라 미러링합니다.
- flip-y
- flip-start
-
start 속성들끼리, end 속성들끼리 값을 교체합니다 (예: margin-block-start와 margin-inline-start 등), 본질적으로 block-start-inline-start 코너에서 block-end-inline-end 코너까지 대각선 기준 미러링입니다.
키워드를 여러 개 지정한 경우, 변환들을 순서대로 합성해 하나의 위치 옵션을 만듭니다. 논리 방향은 writing mode에 따라 포함 블록 기준으로 해석합니다.
- <dashed-ident> || <try-tactic>
-
이전 두 옵션의 효과를 결합합니다: 해당 이름의 @position-try 규칙이 있으면, 그 위치 옵션을 base 스타일에 적용한 뒤, 지정한 <try-tactic>대로 변환하여 결과를 박스의 위치 옵션 리스트에 추가합니다.
없으면 효과 없음.
- <position-area>
-
해당 값의 position-area 속성만으로 구성된 위치 옵션을 자동 생성합니다.
6.2. 폴백 순서 결정: position-try-order 속성
| 이름: | position-try-order |
|---|---|
| 값: | normal | <try-size> |
| 초깃값: | normal |
| 적용 대상: | 절대 위치 박스 |
| 상속 여부: | 아니오 |
| 백분율: | 해당 없음 |
| 계산값: | 지정 값 그대로 |
| 정식 순서: | 문법에 따름 |
| 애니메이션 유형: | 불연속 |
이 속성은 요소가 위치 옵션별로 사용할 수 있는 공간이 더 중요하다면, position-try-fallbacks에 선언된 순서 대신, 각 위치 옵션이 정의하는 가용 공간 크기로 정렬할 수 있게 합니다.
<try-size> = most-width | most-height | most-block-size | most-inline-size
- normal
-
position-try-fallbacks에 지정한 순서대로 위치 옵션을 시도합니다.
- most-width
- most-height
- most-block-size
- most-inline-size
- most-height
-
위치 옵션 리스트의 각 항목에 대해, 해당 위치 옵션을 적용한 후, 그 스타일로 인한 inset-modified 포함 블록의 크기를 구해서 (auto 인셋 값은 0으로 간주함) 이 크기에 따라 위치 옵션 리스트를 가장 큰 것이 먼저 오도록 안정 정렬(stable sort)합니다.
논리 방향 해석은 writing mode에 따라 포함 블록 기준으로 합니다.
.anchor{ anchor-name : --foo; } .list{ position : fixed; position-anchor : --foo; position-area : block-end span-inline-end; position-try-fallbacks : --bottom-scrollable, flip-block, --top-scrollable; position-try-order : most-height; } @position-try --bottom-scrollable{ align-self : stretch; } @position-try --top-scrollable{ position-area : block-start span-inline-end; align-self : stretch; }
기본 스타일 및 --bottom-scrollable 옵션은 모두 앵커에서 포함 블록의 끝까지 inset-modified 포함 블록이 늘어나므로 사용할 수 있는 높이가 같습니다. 마찬가지로 flip-block과 --top-scrollable 옵션도 동일한 높이를 가집니다. position-try-order는 안정 정렬이므로, 이 쌍들은 각각 원래 순서를 유지하며, 더 넓은 쪽이 앞으로 오게 됩니다.
결과적으로 박스는 먼저 더 넓은 쪽에서 자연 높이로 기준에 정렬을 시도하다가 넘치면 해당 공간 전체를 채우며 스크롤 가능하도록(스타일 내 *-scrollable 사용) 후퇴하여, 더 작은 공간으로 바로 이동하지는 않게 됩니다.
6.3. position-try 축약 속성
| 이름: | position-try |
|---|---|
| 값: | <'position-try-order'>? <'position-try-fallbacks'> |
| 초깃값: | 각 속성별 참조 |
| 적용 대상: | 각 속성별 참조 |
| 상속 여부: | 각 속성별 참조 |
| 백분율: | 각 속성별 참조 |
| 계산값: | 각 속성별 참조 |
| 애니메이션 유형: | 각 속성별 참조 |
| 정식 순서: | 문법에 따름 |
이 축약 속성은 position-try-fallbacks와 position-try-order를 모두 설정합니다. <'position-try-order'>가 생략되면, 해당 속성의 초깃값이 사용됩니다.
6.4. @position-try 규칙
@position-try 규칙은 특정 이름의 위치 옵션을 정의하며, 여러 개의 위치 지정 속성 집합을 지정하여 position-try-fallbacks를 통해 박스에 적용할 수 있습니다.
@position-try 규칙의 문법은 다음과 같습니다:
@position-try <dashed-ident> {
<declaration-list>
}
전주에 명시된 <dashed-ident>가 규칙의 이름입니다. 같은 이름으로 @position-try 규칙이 여러 개 선언된 경우, @keyframe 규칙과 동일하게 카스케이드(cascade)됩니다.
@position-try 규칙에서는 다음 속성만 허용됩니다:
<declaration-list> 내 속성에 !important를 사용하면 해당 속성은 무효가 되지만, @property-try 규칙 전체가 무효가 되진 않습니다.
@position-try 내 모든 속성은 위치 폴백 오리진(Position Fallback Origin)의 일부로 박스에 적용되며, 이 오리진은 Author Origin 과 Animation Origin 사이에 위치하는 새로운 카스케이드 오리진(cascade origin)입니다.
Animation Origin과 마찬가지로 revert 값을 사용하면, 해당 속성이 Author Origin의 일부였던 것처럼 동작하여, 대신 User Origin으로 되돌아갑니다. (단, Animation Origin처럼, revert-layer는 특별한 동작 없이 명시된 대로 동작합니다.)
참고: 허용되는 @position-try 속성들은 박스 자기 자신의 크기와 위치에만 영향을 미치며, 내용물이나 스타일에는 영향을 주지 않는 최소 범위의 속성입니다. 이로써 위치 폴백 구현을 단순화하면서도 공간에 따른 앵커 위치 지정 박스 이동이라는 본질적 과제를 해결할 수 있게 됩니다. 이런 규칙들은 Author Origin의 선언을 덮어쓰기 때문에 @position-try 선언과 다른 속성의 일반적인 상속·카스케이드 충돌을 방지합니다. 향후 컨테이너 쿼리(container query) 등 확장에서 요소의 위치 폴백별 조건부 스타일링 지원이 기대됩니다. (현 제한적 속성 리스트로는 불가)
참고: 여러 요소가 같은 @position-try 규칙을 쓰고자 할 때, 각자 자신의 앵커 요소를 기준으로 쓰려면 <anchor-name>을 anchor()에 명시하지 말고, 각 박스의 position-anchor에서 각자 지정하세요.
참고: 가장 일반적인 폴백 위치 지정(기본적으로 한쪽, 넘치면 반대로 "플립")은 position-try-fallbacks의 키워드만으로도 쓸 수 있고, @position-try는 필요 없습니다.
6.5. 위치 폴백 적용
위치 지정 박스가 (기본 스크롤 시프트를 적용한 후) inset-modified 포함 블록을 넘치고, 위치 옵션 리스트에 두 개 이상 위치 옵션이 있을 경우, 위치 폴백 스타일 결정을 실행해 넘침 없는 옵션을 찾으려고 시도합니다. 적용 결과 스타일은 스타일·레이아웃 인터리빙으로 요소에 적용돼 계산값에도 반영되므로(트랜지션 등 발생 가능) 레이아웃·사용값에 의존해도 처리됩니다.
구현체는 과도한 레이아웃 비용 제한을 위해 위치 옵션 리스트 길이에 임의로 제한을 둘 수 있습니다. 단, 이 제한은 최소 다섯 이상이어야 합니다.
-
current styles를 abspos의 현재 사용 스타일로 둡니다 (이전 폴백 적용 결과일 수 있음).
-
위치 옵션 리스트의 각 option에 대해:
-
option이 현재 abspos의 마지막 성공 위치 옵션이면 다음으로 진행.
-
adjusted styles를, 해당 위치 옵션을 적용한 결과로 둡니다.
-
el rect를 abspos의 margin box의 크기·위치, cb rect를 abspos의 inset-modified 포함 블록의 크기·위치로 해당 스타일로 레이아웃한 상태로 둡니다.
-
cb rect가 어느 축이든 음수 크기였다가 0 크기로 보정된 경우, 다음으로 진행.
참고: 이 방어로, 0 크기 el rect가 음수 크기 cb rect에 여전히 "포함"되어 성공 옵션으로 고르는 것을 막습니다.
-
el rect가 cb rect 안에 완전히 포함되지 않으면, 다음으로 진행.
-
adjusted styles와, 가상으로 계산된 기억된 스크롤 오프셋 집합을 반환합니다.
-
-
이전 단계에서 넘침을 피하는 위치 옵션을 찾지 못해 루프가 끝났음을 확인(Assert)합니다.
-
current styles를 반환합니다.
참고: 자식 요소가 abspos를 넘치는 것은 이 계산에 영향을 주지 않습니다. 오직 abspos의 margin box만 기준입니다.
참고: 일부러 현재 적용된 위치 옵션을 건너뛰므로, 그 기억된 스크롤 오프셋은 갱신되지 않습니다. 다른 폴백이 실패해서 기존 스타일을 계속 쓴 경우 기억된 스크롤 오프셋도 그대로 유지됩니다.
전체 레이아웃 단계 중 한 박스가 폴백 스타일을 결정하고(혹은 폴백 없음으로 결정하고) 나면, 이후 레이아웃되는 요소가 이 결정을 바꿀 수 없습니다.
즉, 레이아웃은 "뒤로 가지 않습니다".
6.5.1. 폴백 선택 유지 및 해제
박스에 대한 특정 변경은 위치 폴백 스타일 재결정에 직결적 영향을 주며, 특수 동작을 유발합니다. 이런 폴백 민감 변경(fallback-sensitive changes)은 아래와 같습니다:
-
position-try의 longhand 중 계산값이 바뀐 경우
-
허용된 @position-try 속성의 계산값이 바뀐 경우
-
참조된 @position-try 규칙이 추가/제거/변경된 경우
최대한 레이아웃의 안정성을 확보하기 위해 위치 폴백 스타일 결정은 마지막 성공 위치 옵션을 우선시합니다. 다음 기준입니다:
ResizeObserver
이벤트 산출·전달 시점에, 박스는 다음처럼 마지막 성공 위치 옵션 기록을 해야 합니다:
-
el에 마지막 성공 위치 옵션이 이미 있다면, 마지막 성공 위치 옵션은 폴백 민감 변경이 있으면 제거합니다. 그 다음 폴백 스타일 결정을 하여 마지막 성공 위치 옵션을 현재 허용된 @position-try 속성(값 포함)으로 갱신합니다.
-
없고 el이 절대 위치라면, 마지막 성공 위치 옵션을 현재 사용 중인 허용된 @position-try 속성(값 포함)으로 설정합니다.
참고: 이 기록 및 제거 타이밍은 last remembered sizes와 일치합니다.
6.5.2. 위치 옵션 적용
-
new styles를 위치 폴백 오리진에서 카스케이드에 삽입한 뒤, 카스케이드를 해석하고, el의 사용된 스타일을 산출할 만큼의 레이아웃을 수행한다.
이 스타일들을 계산하기 위해, 가상 앵커 재계산 지점을 계산하고, 그로부터 얻은 가상의 기억된 스크롤 오프셋을 이용해 el의 스타일을 결정한다.
-
el의 사용된 스타일을 반환한다.
-
directions이 같은 축에서 반대라면 “opposing”, 다른 축이라면 “perpendicular”입니다.
-
el에 허용된 @position-try 속성의 지정 값을 구해, styles로 둡니다.
-
var 치환, env() 함수, 및 그 외 임의 치환 함수를 styles에 적용합니다.
env() 함수에 대해 참조된 환경 변수가 축 혹은 방향 관련이면 (예: safe-area-inset-top 등) directions에 맞는 것으로 참조 환경 변수를 바꿔줍니다.
예: top: env(safe-area-inset-top);로 지정돼 있고 directions가 up, left라면, env()는 env(safe-area-inset-left)로 동작. (그리고 다음 단계에서 left 속성으로 치환됨) -
directions에 해당하는 관련 속성들끼리 styles 값을 교체합니다.
참고: 같은 축 반대 방향이면, width나 align-self 등 일부 속성은 자체 축 대응이라 바뀌지 않으며, 다음 단계에서 값만 조정될 수 있습니다.
-
다음과 같이, 교체 후 속성의 값도 새로운 방향에 맞춰 보정합니다:
-
inset 속성은 anchor() 함수 내 지정 변도 새 방향에 맞는 상대 관계로 바꿔줍니다. <percentage> 사용시 반대 방향이면 100% - 원래 값으로 바꿔줍니다.
예: "top"과 "left"를 교체한다면, margin-top: anchor(bottom) → margin-left: anchor(right)"top"과 "bottom"을 교체할 때 margin-top: anchor(20%) → margin-bottom: anchor(80%)
-
크기 속성은 anchor-size() 함수 내 지정 축도 새 방향에 맞는 상대 관계로 바꿔줍니다.
-
self-alignment 속성은 반대 방향이면 self-position·left/right 키워드 등도 동일한 상대 관계로 조정합니다.
예: "top"과 "bottom" 교체시 align-self: start → align-self: end단, align-self: center는 양쪽 모두 동일해 변하지 않습니다.
마찬가지로 align-self: first baseline도, self-position이 아닌 baseline-position이기 때문에 변하지 않습니다.
-
position-area는 position-area 그리드에서 선택된 행/열이 원래와 동일한 관계를 갖게 값 변경.
-
-
styles를 반환합니다.
6.6. 조건부 숨김: position-visibility 속성
| 이름: | position-visibility |
|---|---|
| 값: | always | [ anchors-valid || anchors-visible || no-overflow ] |
| 초깃값: | anchors-visible |
| 적용 대상: | 절대 위치 박스 |
| 상속 여부: | 아니오 |
| 백분율: | 해당 없음 |
| 계산값: | 지정 값 그대로 |
| 정식 순서: | 문법에 따름 |
| 애니메이션 유형: | 불연속 |
일부 조건에서는 절대 위치 박스를 표시하는 것이 의미 없을 수 있습니다. 이 속성을 이용하면 이런 박스의 표시 여부를 자주 필요한 레이아웃 조건에 따라 조건부로 제어할 수 있습니다.
- always
-
이 속성은 아무 효과가 없습니다. (앵커나 오버플로우 여부 상관없이 박스가 표시됩니다.)
- anchors-valid
-
박스의 필수 앵커 참조 중 하나라도 대상 앵커 요소로 해석되지 않으면, 박스의 visibility 속성은 으로 계산됩니다.
필수 앵커 참조란? 폴백 값 없는 anchor() 함수; 기본 앵커는 경우에 따라? 추가 설명 필요.
하나라도 앵커가 없으면? 모두 없으면? 두 케이스 모두 활용 예 있음. 고정인지 선택 가능하게 할지 결정해야 함.
- anchors-visible
-
박스에 기본 앵커 박스가 있지만, 해당 앵커 박스가 보이지 않거나 중간 박스에 의해 클리핑된 경우에는, 박스의 visibility 속성은 으로 계산됩니다.
- no-overflow
-
박스가 inset-modified 포함 블록을 position-try 적용 후에도 넘치면, 박스의 visibility 속성은 으로 계산됩니다.
anchor가 중간 박스에 의해 클리핑됨인지 확인은 문서의 내용 관련성 업데이트 후 (자세한 것은 content-visibility [css-contain-2] 참고) 그리고 ResizeObserver 실행 후, IntersectionObserver 실행 전 확인해야 합니다. 성능 향상을 위해 수시로 판단해도 무방합니다.
참고: 예를 들어 abspos가 DOM에서 자신의 앵커 바로 옆에 있으면, 기본 앵커가 스크롤로 사라져도 동일한 스크롤러에 의해 클리핑되므로 계속 보이게 됩니다.
View Transitions에서 원하는 개념과 이 클리핑 정의의 일치도 확인 필요.
참고: "연쇄 앵커(chained anchor)" 구조에서, 이 속성에 의해 첫 번째 abspos가 숨겨지면 (앵커가 스크롤 등으로 클리핑되어), 그것에 앵커링된 다른 abspos도 숨겨져, 의미 없는 위치에 "붕 뜨는" 일이 방지됩니다.
7. 접근성 영향
CSS 앵커 위치 지정은 요소 간의 접근성 바인딩을 생성, 삭제 또는 변경하지 않습니다. 작성자는 이러한 바인딩을 별도의 마크업 기능으로 반드시 직접 제어해야 합니다.
이 기능은 여러 용도로 다양하게 사용될 수 있으므로, CSS 앵커 위치 지정이 위치 지정 박스와 앵커 간에 어떤 의미론적(semantic) 관계도 자동으로 설정하지 않습니다. 예를 들어, 디자인상 시각적 앵커링 관계가 요소와 의미론적 앵커일 수도 있고, 원하는 시각 효과에 따라 요소가 의미 앵커의 상위/형제/자식일 수 있습니다. 또는 의미 관계는 있으면서 시각적 앵커링은 피할 수도, 그 반대일 수도 있습니다.
작성자는 CSS 위치 지정에서 암시되는 시각적 관계에만 의존해 요소끼리 의미 연결이 있다고 간주해서는 안 됩니다. 올바른 마크업 없이는, 시각적으로 연결된 요소가 아무런 DOM 구조상 의미 관계도 없게 되고—심지어 의미 관계가 있다 해도 비시각적 에이전트(스크린리더 등)ㆍ비그래픽 탐색(탭 이동 등)에서는 사용이 어렵거나 불가능할 수 있습니다.
웹 플랫폼 내 여러 기능(기존, 추가 예정 양쪽 모두)은 시맨틱 연결을 명시적으로 제공할 수 있으므로, 비시각적 사용자 에이전트도 혜택을 받을 수 있습니다. 예를 들어 HTML의 Popover API는 연동 버튼을 팝오버 요소에 자동 연결해주고, 탭 순서까지 자동 조정됩니다. 이 때 팝오버 API는 연동 버튼을 팝오버의 암시적 앵커 요소로 만들어, 앵커 위치 지정의 활용도 쉽게 할 수 있습니다.
일반적으로는,
aria-details
또는 aria-describedby 같은
ARIA 속성을 앵커 요소에 지정하고,
해당 위치 지정 요소에는
role
속성을 지정해
요소 간 의미적 연결을 어느 정도 수작업으로 할 수 있습니다.
이렇게 하면 비시각적 사용자 에이전트가
요소 관계를 사용자에게 설명하거나 자동 탐색을 지원할 수 있습니다.
하지만 이런 기능도 과다하게 남용하면 불필요한 의미적 연결이 너무 많아져 오히려 페이지 이해를 어렵게 만들 수 있으니 주의해야 합니다.
본 섹션에서 저자 안내·모범 사례 예시 등 개선 제안은 환영합니다. [이슈 #10311]
8. DOM 인터페이스
8.1. CSSPositionTryRule 인터페이스
CSSPositionTryRule
인터페이스는
@position-try 규칙을 나타냅니다:
[Exposed =Window ]interface :CSSPositionTryRule CSSRule {readonly attribute CSSOMString name ; [SameObject ,PutForwards =cssText ]readonly attribute CSSPositionTryDescriptors style ; }; [Exposed =Window ]interface :CSSPositionTryDescriptors CSSStyleDeclaration {attribute CSSOMString ;margin attribute CSSOMString ;marginTop attribute CSSOMString ;marginRight attribute CSSOMString ;marginBottom attribute CSSOMString ;marginLeft attribute CSSOMString ;marginBlock attribute CSSOMString ;marginBlockStart attribute CSSOMString ;marginBlockEnd attribute CSSOMString ;marginInline attribute CSSOMString ;marginInlineStart attribute CSSOMString ;marginInlineEnd attribute CSSOMString ;margin-top attribute CSSOMString ;margin-right attribute CSSOMString ;margin-bottom attribute CSSOMString ;margin-left attribute CSSOMString ;margin-block attribute CSSOMString ;margin-block-start attribute CSSOMString ;margin-block-end attribute CSSOMString ;margin-inline attribute CSSOMString ;margin-inline-start attribute CSSOMString ;margin-inline-end attribute CSSOMString ;inset attribute CSSOMString ;insetBlock attribute CSSOMString ;insetBlockStart attribute CSSOMString ;insetBlockEnd attribute CSSOMString ;insetInline attribute CSSOMString ;insetInlineStart attribute CSSOMString ;insetInlineEnd attribute CSSOMString ;top attribute CSSOMString ;left attribute CSSOMString ;right attribute CSSOMString ;bottom attribute CSSOMString ;inset-block attribute CSSOMString ;inset-block-start attribute CSSOMString ;inset-block-end attribute CSSOMString ;inset-inline attribute CSSOMString ;inset-inline-start attribute CSSOMString ;inset-inline-end attribute CSSOMString ;width attribute CSSOMString ;minWidth attribute CSSOMString ;maxWidth attribute CSSOMString ;height attribute CSSOMString ;minHeight attribute CSSOMString ;maxHeight attribute CSSOMString ;blockSize attribute CSSOMString ;minBlockSize attribute CSSOMString ;maxBlockSize attribute CSSOMString ;inlineSize attribute CSSOMString ;minInlineSize attribute CSSOMString ;maxInlineSize attribute CSSOMString ;min-width attribute CSSOMString ;max-width attribute CSSOMString ;min-height attribute CSSOMString ;max-height attribute CSSOMString ;block-size attribute CSSOMString ;min-block-size attribute CSSOMString ;max-block-size attribute CSSOMString ;inline-size attribute CSSOMString ;min-inline-size attribute CSSOMString ;max-inline-size attribute CSSOMString ;placeSelf attribute CSSOMString ;alignSelf attribute CSSOMString ;justifySelf attribute CSSOMString ;place-self attribute CSSOMString ;align-self attribute CSSOMString ;justify-self attribute CSSOMString ;positionAnchor attribute CSSOMString ;position-anchor attribute CSSOMString ;positionArea attribute CSSOMString ; };position-area
name 속성은
규칙 서문에서 선언된 이름을 나타냅니다.
style 속성은
규칙 본문에서 선언된 속성들을 지정된 순서대로 나타냅니다.
값을 얻을 때, CSSPositionTryDescriptors
객체를 반환해야 하며,
@position-try at-rule에 대해 다음과 같은 속성을 포함합니다:
- computed flag
-
설정되지 않음
- readonly flag
-
설정되지 않음
- declarations
-
규칙에서 선언된 descriptor들이 지정된 순서대로 포함됩니다.
- parent CSS rule
-
컨텍스트 객체
- owner node
-
Null
9. 부록: 스타일 & 레이아웃 인터리빙
스타일 & 레이아웃 인터리빙은 스타일 업데이트가 레이아웃 과정 중 서브트리에 발생하여, 요소의 계산된 스타일을 소급해 갱신하는 기법입니다.
이 개념은 여기에 맞는 명세가 아니며, 아마 Cascade에 들어가야 하지만, 참고용 개요가 필요해 여기에 둡니다.
참고: 스타일 & 레이아웃 인터리빙은 이미 컨테이너 쿼리와 컨테이너 쿼리 길이에도 사용됩니다. 10cqw와 같은 길이는 쿼리 컨테이너의 크기 레이아웃 정보를 이용해 계산된 길이로 해석되며, 컨테이너 크기가 레이아웃마다 바뀌면 트랜지션도 트리거될 수 있습니다.
허용된 @position-try 속성도 대체 해석 시 인터리빙됩니다 (position-try 참고).
당연히 훨씬 더 많은 세부 내용이 필요하지만, "컨테이너 쿼리에서 하는 대로 동작" 정도면 충분합니다. 그 동작도 정의되어 있진 않지만, 적어도 어느 정도 상호운용성이 있습니다.
10. 보안 고려사항
이 문서에 대해 보고된 보안 이슈는 없습니다.
11. 프라이버시 고려사항
이 문서에 대해 보고된 프라이버시 이슈는 없습니다.
12. 변경 사항
2025년 10월 7일 워킹드래프트 이후의 주요 변경 사항:
-
flip-x와 flip-y가 position-try-fallbacks에 추가됨. (이슈 12869)
-
anchor-center가 scrollable containing block도 사용하는 것으로 정의됨, 이로써 local containing block 밖에 위치할 때 오버플로우 정렬을 유발하지 않음. (이슈 12952)
-
position-area 또는 anchor-center가 적용될 때 auto 마진을 0으로 해석하도록 함, 팝오버용 HTML UA 기본 스타일시트 규칙에 의한 문제 때문. dialog 정렬 값(이전 대책)은 삭제됨. (이슈 10258)
-
none 값을 position-anchor에 추가, 이 값을 초기값으로 하여 암시적 앵커 요소가 있는 모든 절대 위치 박스가 scrollable containing block을 쓰지 않도록 함. 초기값은 논의 중이라 앞으로 또 바뀔 수 있음... (이슈 13067)
-
flip-block, flip-inline, flip-start는 writing mode가 containing block 기준임을 명확화. (이슈 12869, 이슈 13076)
-
auto inset 값은, inset-modified 포함 블록 크기 계산시 0으로 처리, position option을 position-try-order로 비교할 때 적용함을 명확화. (이슈 12942)
-
clip-path도 anchors-visible 체크대상에 포함, 체크 시점에 대해서도 명확하게 함. (이슈 12732)
-
기본 스타일이 position options list에 빠지는 오류 수정. (이슈 12890)
-
anchors-visible 체크의 타이밍 명확화. (이슈 12732)
-
normal 정렬 해석이 position-area 값에 따라 사용 값에 직접 영향을 주며, 이 사용 값이 오버플로우 처리 방식에 연동됨을 명확히 함 ([CSS-ALIGN-3]).
-
앵커 이름 매칭시 트리 루트 일치가 필요하던 알고리즘 오류 수정, 섀도우 트리 경계 너머로 매칭될 수도 있음을 반영. (이슈 12941)
-
auto inset 값은 inset-modified 포함 블록 크기를 position-try-order에서 계산할 때 0으로 처리함을 명확화. (이슈 12942)
-
§ 6 Overflow Management와 § 2 Determining the Anchor 설명 구조 재편. (이슈 12818, 이슈 11022)
-
§ 7 접근성 영향의 가이드 보완, UA 요구사항 명확화. (이슈 10311)
-
예시 개선.
이전 변경 내역은 Previous Changes 참고.