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에서 선택자 매칭 외 대부분의 동작과 마찬가지로, 이 명세서의 기능은 평탄화된 요소 트리에서 동작합니다.
2. 앵커 결정하기
2.1. 앵커 생성: anchor-name 속성
이름: | anchor-name |
---|---|
값: | none | <dashed-ident># |
초기값: | none |
적용 대상: | 주요 박스를 생성하는 모든 요소principal box |
상속됨: | 아니오 |
백분율: | 해당 없음 |
계산된 값: | 명시된 대로 |
정규 순서: | 문법에 따름 |
애니메이션 타입: | 이산형 |
anchor-name 속성은 해당 요소가 앵커 요소임을 선언하며, 그 principal box가 앵커 박스가 되고, 타겟이 될 앵커 이름 목록을 지정합니다. 값은 다음과 같이 정의됩니다:
- none
-
속성이 아무런 효과도 주지 않습니다.
- <dashed-ident>#
-
요소가 principal box를 생성하는 경우, 해당 요소는 앵커 요소이며, 명시된 앵커 이름 목록을 갖습니다. 각 앵커 이름은 느슨하게 매칭된 트리 범위 이름입니다.
그 외에는 속성이 아무런 효과도 주지 않습니다.
앵커 이름은 고유할 필요가 없습니다. 모든 요소가 반드시 타겟 앵커 요소가 될 수 있는 것은 아닙니다. 따라서 이름을 여러 곳에서 재사용할 수 있으며, 사용 범위가 적절히 한정된다면 가능합니다.
참고: 여러 요소가 동일한 앵커 이름을 공유하며, 모두 특정 위치 지정 박스에서 볼 수 있을 경우, 타겟 앵커 요소는 DOM 순서상 마지막 요소가 됩니다. anchor-scope 속성을 사용하면 특정 참조 박스에서 볼 수 있는 이름을 더 제한할 수 있습니다.
앵커 이름은 기본적으로 containment로 범위가 지정되지 않습니다; 요소에 스타일 또는 레이아웃 containment (혹은 그와 유사한 containment)이 있더라도, 그 자식들의 앵커 이름은 페이지 내 다른 요소에서도 볼 수 있습니다.
참고: 요소가 다른 요소의 스킵된 컨텐츠에 있을 경우 (예: content-visibility: hidden 등), 해당 요소는 허용 가능한 앵커 요소가 아니며, 사실상 이름이 없는 것처럼 동작합니다.
참고: 섀도우 트리 내의 위치 지정 요소는 "상위" 트리에 정의된 앵커 이름을 참조할 수 있습니다. 현재는 "하위" 섀도우 트리에서 정의된 앵커 이름은 참조할 수 없습니다.
2.1.1. 암시적 앵커 요소
일부 명세에서는, 특정 상황에서, 특정 요소가 다른 요소의 암시적 앵커 요소가 된다고 정의할 수 있습니다.
TODO: HTML 명세에 새로운 popover 관련 내용이 반영되면 예시 추가 예정
암시적 앵커 요소는 auto 키워드를 position-anchor에서 사용하거나, 앵커 함수에서 앵커 참조를 생략함으로써 참조할 수 있습니다.
암시적 앵커 요소의 의사 요소는 달리 명시하지 않는 한 원본 요소가 됩니다.
2.1.2. 앵커 박스
이 명세의 여러 기능은 앵커 박스의 위치와 크기를 참조합니다. 별도의 명시가 없는 한, 이는 border box 엣지를 principal box의 앵커 요소 기준으로 가리킵니다. 앵커 박스의 위치와 크기는 레이아웃 후에 결정됩니다.
이 위치와 크기에는 zoom 및 position 기반의 조정 (예: position: relative 또는 position: sticky) 그리고 변형(transform, 예: transform 또는 offset-path)도 포함됩니다. 이런 경우, 앵커 박스의 축 정렬 경계 사각형이 절대 위치 지정 요소의 포함 블록의 좌표 공간에 맞춰서 사용됩니다. 변형(transform)은 종종 별도의 스레드에서 최적화되어, 앵커 박스의 위치에 대한 변형 기반 업데이트가 몇 프레임 지연될 수 있습니다. 작성자는 절대 또는 상대 위치 지정을 사용함으로써 이런 지연을 피할 수 있습니다.
앵커 박스가 분할(fragmented)되어 있고, 포함 블록이 절대 위치 지정 박스가 참조하는 앵커 박스의 관련 분할 컨텍스트(fragmentation context) 외부에 있다면, 박스 분할(box fragments)의 축 정렬 경계 사각형이 대신 사용됩니다. (절대 위치 박스가 분할 컨텍스트 내부에 있으면, 앵커 박스를 분할되지 않은 것으로 보고—자신도 분할 컨텍스트에 의해 분할될 수 있습니다.)
성능상의 이유로, 스크롤링은 별도로 다루며, § 3.3 스크롤 고려를 참고하세요. 레이아웃 이후 효과(예: 필터 등)는 앵커 박스의 위치에는 영향을 주지 않습니다.
2.2. 앵커 이름 범위 지정: anchor-scope 속성
이름: | anchor-scope |
---|---|
값: | none | all | <dashed-ident># |
초기값: | none |
적용 대상: | 모든 요소 |
상속됨: | 아니오 |
백분율: | 해당 없음 |
계산된 값: | 명시된 대로 |
정규 순서: | 문법에 따름 |
애니메이션 타입: | 이산형 |
이 속성은 지정된 앵커 이름과 그 앵커 이름 조회를 해당 요소의 서브트리로 한정합니다. § 2 앵커 결정하기를 참고하세요.
값의 의미는 다음과 같습니다:
- none
- 앵커 이름 범위에 변화가 없습니다.
- all
-
이 요소 또는 그 자손이 정의한 모든 앵커
이름이(자손 중 anchor-scope로 이미 범위가 제한되지 않은 경우)
이 요소의 자손에게만 범위가 적용되도록 지정합니다.
자손은 해당 서브트리 내의 앵커 요소에서만
앵커 이름을 매칭할 수 있습니다.
이 값은 같은 트리 범위 내의 앵커 이름에만 영향을 주며, 엄격 매칭 트리 범위 이름처럼 동작합니다. (즉, anchor-scope: all은 anchor-scope: --foo, --bar, ...와 동일하게 동작하며, 관련 앵커 이름을 모두 나열합니다.)
- <dashed-ident>
-
이 요소 또는 그 자손이 정의한 일치하는 앵커
이름이(자손 중 anchor-scope로 이미 범위가 제한되지 않은 경우)
이 요소의 자손에게만 범위가 적용되도록 지정합니다.
자손은 해당 서브트리 내의 앵커 요소에서만
앵커 이름을 매칭할 수 있습니다.
<dashed-ident>는 엄격 매칭 트리 범위 이름을 의미하며, 즉 동일한 섀도우 트리내의 앵커 이름만 매칭할 수 있습니다.[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> (그리고 트리 범위 참조)로, 페이지의 다른 곳에 anchor-name 값과 일치해야 하거나, auto 키워드, 혹은 아무것도 없는(지정자 누락) 경우입니다.
참고: 아래 조건이 포괄하는 일반 규칙은 한 요소가 위치 지정 박스의 타겟 앵커 요소가 되려면 자신의 박스 레이아웃이 참조하려는 위치 지정 박스의 레이아웃보다 반드시 먼저 완료되어야 한다는 것입니다. CSS 레이아웃 규칙은 앵커와 위치 지정 박스의 관계, 그리고 포함 블록에 따라 이에 대한 유용한 보장을 제공합니다. 아래 조건 목록은 스택 컨텍스트 규칙을 이 목적에 맞게 재설명한 것으로, 앵커 위치 지정에 순환성이 발생하지 않도록 보장합니다.
-
anchor spec이 전달되지 않았다면, 기본 앵커 요소가 있으면 반환하고, 없으면 아무것도 반환하지 않습니다.
-
anchor spec이 auto인 경우:
-
query el에 암시적 앵커 요소가 있고, 그것이 허용 가능한 앵커 요소라면, 그 요소를 반환합니다.
-
그렇지 않으면 아무것도 반환하지 않습니다.
참고: 향후 API에서도 암시적 앵커 요소를 정의할 수 있습니다. 그때는 이 알고리즘에 명시적으로 처리되어 조정이 이뤄질 수 있습니다.
-
-
그 외의 경우 anchor spec은 <dashed-ident>입니다. 다음 조건들을 만족하는 트리 순서상 마지막 요소 el을 반환합니다:
-
el이 허용 가능한 앵커 요소여야 합니다 (query el 기준).
조건을 만족하는 요소가 없으면, 아무것도 반환하지 않습니다.
참고: anchor-scope는 특정 앵커 이름의 가시성을 제한할 수 있어, 어떤 요소가 앵커 요소가 될 수 있는지에 영향을 미칠 수 있습니다.
참고: 한 anchor-name이 한 섀도우 트리의 스타일에 의해 정의되면, 다른 섀도우 트리의 스타일에서 anchor 함수로는 보이지 않아 캡슐화가 유지됩니다. 하지만 요소는 서로 다른 섀도우 트리 사이에서도 앵커링이 가능하며, anchor-name과 anchor 함수 모두 동일 트리의 스타일에서 유래하면 됩니다. 예를 들어 ::part()로 섀도우 내부 요소를 스타일링할 때처럼. (암시적 앵커 요소도 본질적으로 단일 트리에 한정되진 않으나, 그 세부 사항은 할당하는 API에 따라 달라집니다.)
-
possible anchor가 요소이거나, 완전히 스타일 지정 가능한 트리-속성 의사 요소여야 합니다.
-
possible anchor가 positioned el 기준으로 anchor-scope나 그 조상에 의해 범위에 있어야 합니다.
-
possible anchor가 positioned el보다 반드시 먼저 레이아웃되어야 하며, 다시 말해 다음 중 하나가 참이어야 합니다:
-
possible anchor와 positioned el이 동일한 원본 포함 블록을 갖고, 다음 중 하나:
-
possible anchor가 더 낮은 top layer에 있거나
-
둘 다 동일한 top layer에 존재하며, possible anchor가 절대 위치 지정이 아니거나, positioned el보다 평탄화 트리 순서상 먼저 나타납니다.
-
-
possible anchor의 포함 블록을 생성하는 요소(있다면)가 positioned el에 대해 허용 가능한 앵커 요소여야 합니다.
-
-
possible anchor가 다른 요소의 스킵된 컨텐츠에 있다면, positioned el도 그 요소의 스킵된 컨텐츠에 있어야 합니다.
참고: 즉 positioned el과 possible anchor가 동일한 스킵 "리프"에 있으면 앵커링 할 수 있지만, 서로 다른 리프를 넘어서 앵커링은 불가합니다. 즉 둘을 모두 포함하는 요소를 스킵해도 positioned el이 다른 앵커로 이동하지는 않지만, 페이지의 다른 곳에 있는 위치 지정 요소가 그 스킵된 요소를 앵커링하는 것은 막아줍니다.
2.4. 기본 앵커: position-anchor 속성
이름: | position-anchor |
---|---|
값: | auto | <anchor-name> |
초기값: | auto |
적용 대상: | 절대 위치 박스 |
상속됨: | 아니오 |
백분율: | 해당 없음 |
계산된 값: | 명시된 대로 |
정규 순서: | 문법에 따름 |
애니메이션 타입: | 이산형 |
position-anchor 속성은 기본 앵커 요소를 지정하며, 이는 position-area, position-try, 그리고 (기본적으로) 이 요소에 적용된 모든 앵커 함수에서 사용됩니다. position-anchor는 reset-only 서브 속성이며, position의 하위 속성입니다.
- auto
- <anchor-name>
-
지정된 <anchor-name>으로 선택된 타겟 앵커 요소가 박스의 기본 앵커 요소가 됩니다.
principal box는 기본 앵커 요소의 기본 앵커 박스가 됩니다.
.anchored{ position : absolute; top : calc ( .5 em +anchor ( outside)); /* 앵커 이름을 명시하지 않았으므로, 자동으로 기본 앵커 박스를 참조합니다. */ } .foo.anchored{ position-anchor : --foo; } .bar.anchored{ position-anchor : --bar; }
2.5. 앵커 관련성
요소 el이 사용자에게 관련 있는지 판단할 때, el의 자손 중 하나가 위치 지정 박스의 타겟 앵커 요소라면 (자신이 스킵되지 않았고, 그 포함 블록이 el 또는 그 자손이 아니면), el은 사용자에게 관련 있음으로 간주해야 합니다.
참고: 예를 들어, content-visibility: auto 서브트리의 앵커는 그 서브트리가 스킵되는 것을 막아줍니다. 단, 위치 지정 박스도 스킵되지 않는 경우에만 해당합니다. (앵커와 위치 지정 박스가 모두 동일한 content-visibility: auto 요소 아래에 있으면 서로를 순환적으로 계속 보이게 할 수는 없습니다.)
3. 앵커 기반 위치 지정
절대 위치 박스는 페이지 내 하나 이상의 앵커 박스를 기준으로 자신의 위치를 지정할 수 있습니다.
position-area 속성은 기본 앵커 박스 기준으로 위치를 지정할 수 있는 편리한 그리드 기반 개념을 제공합니다. 더 복잡한 위치 지정이나 여러 박스 기준 위치 지정에는 anchor() 함수를 인셋 속성에서 사용하여 앵커 박스의 엣지를 명시적으로 참조할 수 있습니다.
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 그리드의 영역을 선택하여 박스의 포함 블록으로 만듭니다.
참고: 즉 인셋 속성은 position-area 기준 오프셋을 지정하며, max-height: 100% 등 일부 속성 값도 position-area 기준이 됩니다.
none 이외의 값은 다음 추가 효과가 있습니다:
-
스크롤 가능한 포함 블록이 로컬 포함 블록 대신 사용되어 전체 스크롤 가능한 오버플로우 영역(일반적으로)이 위치 지정에 사용할 수 있게 됩니다.
-
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>로 해석됩니다. 인셋 속성에서만 허용되며(그 외에는 무효입니다).
이름: | 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
-
사용되는 인셋 속성에 따라 앵커 박스의 엣지 중 하나로 해석됩니다. inside는 인셋 속성과 같은 엣지(즉 "inside"로 부착), outside는 반대쪽을 참조합니다.
- top
- right
- bottom
- left
- right
-
앵커 박스의 지정된 엣지를 참조합니다.
참고: 이 값들은 해당 축의 인셋 속성에서만 사용 가능합니다. 예: left는 left, right 또는 논리적 수평 축 인셋 속성에서만 사용.
- start
- end
- self-start
- self-end
- end
-
사용된 인셋 속성의 축 기준으로 앵커 박스의 한 엣지를 참조하며, 키워드는 위치 지정 박스 기준(self-start, self-end) 또는 위치 지정 박스의 포함 블록 기준(start, end)으로 해석.
- <percentage>
- center
-
시작과 끝 엣지 사이의 해당 백분율 위치를 참조, 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로 쉽게 구현 가능. [Issue #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
요소의 오류 메시지에 적합할 수 있으며,
중앙 배치로 어떤 input이 참조되는지 쉽게 알 수 있습니다.
3.2.1. anchor() 해석
anchor() 함수는 아래 모든 조건을 만족할 때만 해석 가능한 anchor 함수입니다:
-
함수가 절대 위치 박스에 적용됩니다.
-
함수의 <anchor-side>가 물리적 키워드를 지정하는 경우, 해당 축에 적용되는 인셋 속성에서 지정해야 합니다. (예: left는 left, right 또는 수평 축의 논리 인셋 속성에서만 사용 가능.)
-
함수가 적용된 박스와 함수 내 지정된 타겟 앵커 요소, <anchor-name> 값이 모두 존재합니다.
이 조건 중 하나라도 거짓이면, anchor() 함수는 지정한 대체값으로 계산됩니다. 대체값이 없으면, 해당 선언은 계산값 단계에서 무효가 됩니다.
3.3. 스크롤 반영
성능상의 이유로, 구현체는 보통 스크롤을 별도의 스크롤/합성(compositing) 스레드에서 처리하는데, 그 스레드는 기능이 매우 제한되어 있습니다 (간단한 이동/변형 등만 가능, 레이아웃 등 무거운 작업은 불가) 그래서 스크롤에 "즉각적"으로 반응하는 것이 가능합니다.
스크롤이 앵커 위치 지정 요소를 이동만 시킨다면, 이론상 문제는 없습니다; 이동은 스크롤 스레드에서 처리되어 위치 지정 요소가 스크롤 콘텐츠와 함께 부드럽게 움직입니다. 하지만 앵커 위치 지정은 요소가 자신의 반대편 엣지 위치를 다른 스크롤 컨텍스트에 따라 다르게 설정할 수 있게 하므로, 스크롤 시 단 한 엣지만 움직여도 크기 변화(레이아웃)를 일으킬 수 있습니다. 이는 스크롤 스레드에서 처리할 수 없습니다!
이를 보완하면서도 다양한 요소에 자유롭게 앵커링할 수 있도록 앵커 위치 지정은 스크롤 오프셋 기억과 스크롤 보상을 조합해 사용합니다.
-
위치 지정 요소가 처음 표시되거나, 대체 위치가 변경될 때는 모든 앵커 참조의 최신 위치로 올바르게 계산합니다.
이 앵커 참조가 다른 스크롤 컨텍스트에 있다면, 총 스크롤 오프셋을 기억하고 이후 해당 요소가 스크롤되더라도 기억된 오프셋을 계속 사용합니다. (기억하는 것은 오프셋뿐이며, 실제 레이아웃 위치는 매번 새로 계산되어 정확도를 유지합니다.) 위치 지정 요소가 표시되지 않다가 다시 나타나거나, 대체 위치가 변경되면 재계산합니다.
-
예외는 기본 앵커 요소입니다; 해당 요소가 기억된 스크롤 오프셋에서 스크롤되면, 위치 지정 요소도 함께 이동합니다. 이 동작은 오직 위치 이동만 일으키므로, 위치 지정 요소의 크기 변화나 추가 레이아웃은 발생하지 않습니다.
결과적으로 앵커 위치 지정은 어떤 요소를 앵커로 삼든 "그냥 동작"해야 하지만, 스크롤에 대한 반응에는 한계가 있을 수 있습니다.
요소에 대해 대체 위치 스타일 결정 시에도 앵커 재계산 시점이 발생하며, 대체 스타일이 바뀌면 선택된 대체 스타일에 연결된 앵커 재계산 시점 결과를 사용합니다.
요소 abspos에 대해 앵커 재계산 시점이 발생하면, abspos의 앵커 참조 중 하나라도 참조하는 요소 anchor마다 기억된 스크롤 오프셋을 연결합니다. 이는 현재 스크롤 오프셋 합과 같으며, anchor의 모든 스크롤 컨테이너 조상(단, abspos의 포함 블록은 제외)까지 계산합니다. 기억된 스크롤 오프셋은 position: sticky 등 다른 스크롤 의존 위치 변화도 반영합니다. abspos가 기본 앵커 요소를 갖고 있으면, 기억된 스크롤 오프셋을 항상 계산합니다 (비록 실제 앵커 참조가 없어도).
모든 앵커 참조는 모든 스크롤 컨테이너가 초기 스크롤 위치에 있다고 가정하고 계산되며, 그 후 연결된 기억된 스크롤 오프셋만큼 더해집니다.
변형(transform)도 스크롤과 같은 문제가 있으므로, 앵커 위치 지정에서도 보통 무시합니다. 여기서 변형 효과까지 포함할 수 있을까요?
위 방식으로 위치 지정 요소는 앵커 참조의 스크롤 위치에 한 번 반응할 수 있지만, 참조 요소가 스크롤되면 더 이상 앵커에 고정된 것처럼 보이지 않습니다 (비록 스크롤 이외의 움직임에는 계속 반응합니다). 이 문제는 일반적으로 해결할 수 없지만, 한 개 앵커 참조에는 반응 가능합니다; 구체적으로 기본 앵커 요소입니다:
-
abspos에 기본 앵커 박스가 있습니다.
-
abspos가 앵커 참조로 기본 앵커 박스 또는 같은 스크롤 컨텍스트 내의 요소를 참조합니다, 즉 다음 중 하나:
-
abspos의 해당 축 self-alignment 속성이 anchor-center인 경우;
-
abspos의 none이 아닌 position-area 값이 있는 경우
-
abspos의 사용된 인셋 속성 중 하나라도 anchor() 함수가 동일한 가장 가까운 스크롤 컨테이너 조상을 갖는 타겟 앵커 요소를 참조하는 경우.
-
참고: abspos에 position options list가 있다면, 어느 축에서 스크롤을 보상하는지는 적용된 대체 스타일에도 영향을 받습니다.
abspos의 기본 스크롤 이동량은 각각 수평, 수직 축에 대해 길이쌍입니다. 각 길이는 다음과 같이 계산합니다:
-
abspos가 해당 축에서 스크롤을 보상하면, 기본 앵커 요소의 기억된 스크롤 오프셋과 새로운 재계산 시점의 기억된 스크롤 오프셋 차이로 계산합니다.
-
그 외에는 길이는 0입니다.
abspos의 레이아웃 수행 후에는 기본 스크롤 이동량만큼 추가로 이동하며, 이는 transform의 영향을 받은 것처럼 처리됩니다 (다른 변형 전에).
스냅샷의 정확한 타이밍 정의 필요: 매 프레임, 스타일 재계산 전에 갱신.
기억된 스크롤 오프셋과 유사하게, 기본 앵커 요소의 변형(transform)도 반영할 수 있을까?
참고: 기억된 스크롤 오프셋은 anchor() 함수의 값에 영향을 주지만, 기본 스크롤 이동량은 인셋 속성 값과 정렬 이후 직접 요소를 이동시킵니다. 이는 일반적으로 구분이 어렵지만, round(anchor(outside), 50px)처럼 기본 앵커 요소 위치를 비선형 방식으로 변형할 때 동작 차이가 드러납니다.
4. 앵커 기반 정렬
4.1. 영역별 기본 정렬
position-area가 none이 아니면, normal self-alignment 값의 동작이 <position-area> 값에 따라 달라집니다. 박스를 앵커 쪽으로 정렬하기 위해:
-
한 축에서 center 트랙만 선택된 경우, 해당 축의 기본 정렬은 center입니다.
-
모든 3개 트랙이 선택된 경우, 해당 축의 기본 정렬은 anchor-center입니다.
-
그 외에는 해당 축에서 지정되지 않은 사이드 트랙 방향으로 정렬합니다: 예를 들어 “start” 트랙을 지정하면 해당 축의 기본 정렬은 end 등입니다.
단, 관련 축의 인셋 속성 중 하나만 auto라면, 기본 정렬은 auto가 아닌 인셋 쪽으로, 그리고 이는 unsafe 정렬입니다.
참고: 이 단일 auto 동작은 단일 인셋 지정이 절대 위치 박스의 위치를 제어하는 방식을 유지합니다.
이 동작은 위치 지정 박스가 예상보다 작은 포함 블록에서도 박스가 보이고 의도한 경계 내에 머물 가능성을 높여줍니다.
예를 들어 position-area: bottom span-right 값은 앵커의 왼쪽 엣지부터 포함 블록의 오른쪽 엣지까지 박스를 늘리며, 기본적으로 왼쪽 정렬됩니다. 만약 박스가 그 공간보다 크면(예: 앵커가 화면 오른쪽에 너무 가까울 때), 박스는 보이도록 왼쪽으로 이동합니다.
4.2. 앵커 중심 정렬: anchor-center 정렬 값
이름: | justify-self, align-self, justify-items, align-items |
---|---|
새 값: | anchor-center |
self-alignment 속성은 절대 위치 박스가 inset-modified 포함 블록 내에서 정렬할 수 있게 해줍니다. 기존 값과 적절한 인셋 속성만으로도 대부분 유용한 정렬이 가능하지만, 앵커 기반 위치 지정의 대표적 사례인 “앵커 박스 위 중앙 정렬”은 복잡한 설정이 필요합니다.
새로운 anchor-center 값은 이 경우를 아주 쉽게 만듭니다: 위치 지정 박스에 기본 앵커 박스가 있으면 해당 축에서(가능한 한) 기본 앵커 박스 위에 중앙 정렬됩니다.
박스가 절대 위치 박스가 아니거나 기본 앵커 박스가 없으면, 이 값은 center와 같으며 인셋 속성 해석에 추가 효과는 없습니다.
참고: anchor-center 사용 시 앵커가 박스의 원본 포함 블록 가장자리에 너무 가까우면 완전히 중앙에서 “이동”하여 원본 포함 블록 내에 남게 됩니다. 자세한 내용은 CSS Box Alignment 3 § 4.4 Overflow Alignment: the safe and unsafe keywords and scroll safety limits 참고.
4.3. 조건부 중앙 정렬: dialog 정렬 값
이름: | justify-self, align-self, justify-items, align-items |
---|---|
새 값: | dialog |
다이얼로그 박스는 보통 화면 중앙에 표시되지만, 다른 요소에 앵커링되는 경우도 있습니다.
새로운 dialog 값은 이런 동작을 지정할 수 있게 해줍니다: 박스가 절대 위치 박스이고 position-area 값이 none이 아니면, normal에 따라 정렬됩니다 (§ 4.1 영역별 기본 정렬 참고); 그 외에는 center에 따라 정렬됩니다.
5. 앵커 기반 크기 조정
절대 위치 박스는 anchor-size() 함수를 크기 속성에서 사용하여 하나 이상의 앵커 박스의 크기를 참조할 수 있습니다. 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의 경우) 또는 박스의 쓰기 모드와 포함 블록 (block, inline의 경우)에 따라 물리적 키워드로 매핑됩니다.
<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. 오버플로우 관리
앵커 위치 지정은 강력하지만, 예측 불가능할 수도 있습니다. 앵커 박스는 페이지 어디에나 있을 수 있으므로, 박스를 특정 방식(예: 앵커 위, 앵커 오른쪽 등)으로 위치시키면 위치 지정 박스가 포함 블록을 넘치거나 화면 일부가 밖으로 나갈 수 있습니다.
이를 완화하기 위해 절대 위치 박스는 position-try-fallbacks 속성을 사용하여 여러 대체 위치/정렬 속성(박스의 기존 스타일에서 생성하거나, @position-try 규칙에서 지정)을 참조할 수 있습니다. 박스가 최초 위치에서 오버플로우 되면 UA가 하나씩 시도하며, 포함 블록을 넘치지 않는 첫 옵션을 선택합니다.
position-try-order는 공간 우선 순위가 더 중요할 때 옵션을 공간 크기 기준으로 정렬할 수 있게 해줍니다.
6.1. 대체 옵션 제공: position-try-fallbacks 속성
이름: | position-try-fallbacks |
---|---|
값: | none | [ [<dashed-ident> || <try-tactic>] | <position-area> ]# |
초기값: | none |
적용 대상: | 절대 위치 박스 |
상속됨: | 아니오 |
백분율: | 해당 없음 |
계산된 값: | 명시된 대로 |
정규 순서: | 문법에 따름 |
애니메이션 타입: | 이산형 |
이 속성은 절대 위치 박스가 inset-modified 포함 블록을 넘칠 때 시도할 대체 위치 스타일 목록을 제공합니다. 이 위치 옵션 목록은 초기에는 비어 있습니다.
콤마로 구분된 각 항목은 별도의 옵션이며, @position-try 블록 이름이거나, 박스의 기존 계산 스타일에 대해 자동 변환을 나타내는 <try-tactic>입니다.
값의 의미는 다음과 같습니다:
- none
-
속성이 아무런 효과도 주지 않으며, 박스의 위치 옵션 목록은 비어 있습니다.
- <dashed-ident>
-
지정된 이름의 @position-try 규칙이 있으면, 해당 위치 옵션을 위치 옵션 목록에 추가합니다.
그 외에는 아무런 효과도 없습니다.
- <try-tactic>
-
박스의 계산 스타일에서 위치 옵션을 자동 생성하며, 지정된 키워드에 따라 try-tactic으로 값 교환을 수행하여 생성된 위치 옵션을 박스의 위치 옵션 목록에 추가합니다.
<try-tactic> = flip-block || flip-inline || flip-start
- flip-block
-
block 축의 값을 서로 교환합니다 (예: margin-block-start와 margin-block-end 사이), 즉 inline 축 기준으로 대칭 이동합니다.
- flip-inline
- flip-start
-
start 속성값끼리, end 속성끼리 서로 교환합니다 (예: margin-block-start와 margin-inline-start 등), 즉 start-start 코너에서 end-end 코너로 대각선 기준 대칭 이동합니다.
키워드를 여러 개 지정하면, 변환을 순서대로 조합하여 하나의 위치 옵션을 만듭니다.
- <dashed-ident> || <try-tactic>
-
이전 두 옵션을 결합: 지정된 이름의 @position-try 규칙이 있으면, 해당 위치 옵션을 기본 스타일에 적용한 뒤 지정된 <try-tactic>에 따라 변환하여 박스의 위치 옵션 목록에 추가합니다.
그 외에는 아무것도 하지 않습니다.
- <position-area>
-
지정된 값의 position-area 속성만을 갖는 위치 옵션을 자동 생성합니다.
-
directions가 동일 축의 반대면 “반대(opposing)”이고, 서로 다른 축이면 “수직(perpendicular)”입니다.
-
허용된 @position-try 속성의 지정값을 el에서 확인하고, styles에 저장합니다.
-
변수 치환, env() 함수 등 임의 치환 함수를 styles에 치환합니다.
env() 함수에서 참조된 환경 변수가 방향 또는 축과 연계된다면 (예: safe-area-inset-top), directions에 맞게 참조 환경 변수를 바꿔줍니다.
예: top: env(safe-area-inset-top);이 지정되고, directions가 up, left라면 env()는 env(safe-area-inset-left)로 해석합니다. (다음 단계에서 left 속성으로 실제로 교환됨.) -
styles의 해당 방향에 연계된 속성값을 교환합니다.
참고: 방향이 동일 축의 반대면 일부 속성(width, align-self 등)은 자신과 연관되어 있어 교환되지 않지만, 다음 단계에서 값이 바뀔 수 있습니다.
-
속성값을 교환 방향에 맞게 수정합니다:
-
인셋 속성의 경우, anchor() 함수에서 지정된 방향을 새 방향과 동일한 상대 위치가 되도록 바꿉니다. <percentage>가 사용되었고, directions가 반대면, 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 속성의 경우, directions가 반대면, <self-position> 또는 left/right 키워드를 동일한 상대 위치가 되도록 바꿉니다.
예: "top"과 "bottom"을 교환하면, align-self: start는 align-self: end로 변환.하지만 align-self: center는 변하지 않습니다, 양쪽 방향 모두 동일한 관계이기 때문입니다.
마찬가지로 align-self: first baseline도 변하지 않습니다, 이는 <baseline-position> 값이기 때문입니다.
-
position-area의 경우 position-area 그리드의 선택된 행/열이 새 방향과 동일한 상대 위치가 되도록 값을 바꿉니다.
-
-
styles를 반환합니다.
6.2. 대체 순서 결정: position-try-order 속성
이름: | position-try-order |
---|---|
값: | normal | <try-size> |
초기값: | normal |
적용 대상: | 절대 위치 박스 |
상속됨: | 아니오 |
백분율: | 해당 없음 |
계산된 값: | 명시된 대로 |
정규 순서: | 문법에 따름 |
애니메이션 타입: | 이산형 |
이 속성은 위치 옵션 목록이 시도되는 순서를 지정합니다.
<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 포함 블록 크기를 계산합니다. 이 크기 기준으로 위치 옵션 목록을 안정적으로 정렬하며, 가장 큰 옵션부터 시도합니다.
.anchor{ anchor-name : --foo; } .list{ position : fixed; position-anchor : --foo; position-area : block-end span-inline-end; align-self : start; 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; }
flip-block 자동 생성 옵션과 --top-scrollable 옵션은 포함 블록의 상단 엣지부터 앵커 상단까지 수직으로 늘리므로 항상 동일한 사용 가능한 높이를 찾으며, 지정된 순서를 유지합니다. 박스는 우선 앵커에 자연 높이로 정렬(기본 스타일에서 align-self: end 사용, 자동 반전됨)하려고 시도하지만, 그래도 오버플로우가 발생하면 공간을 채우고 스크롤 가능하게 대체합니다.
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 규칙이 선언되면, cascade 규칙에 따라 결합됩니다(@keyframe 규칙과 동일).
@position-try 규칙은 다음 속성만 허용합니다:
<declaration-list> 내 속성에 !important를 사용하는 것은 무효입니다. 그렇게 하면 해당 속성이 무효가 되지만, @property-try 규칙 전체가 무효가 되진 않습니다.
모든 @position-try 속성은 박스에 Position Fallback Origin 으로 적용되며, 이는 cascade origin에서 저자(origin) 단계와 애니메이션(origin) 단계 사이에 위치합니다.
애니메이션(origin) 단계와 유사하게, revert 값을 사용하면 해당 속성이 저자(origin) 단계에 속한 것처럼 동작하여 대신 사용자(origin) 단계로 되돌립니다. (애니메이션(origin) 단계와 같이 revert-layer는 특별한 동작이 없으며 명시된 대로만 동작합니다.)
참고: 허용된 @position-try 속성은 박스 자체의 크기와 위치에만 영향을 주는 최소한의 속성 그룹이며, 내용이나 스타일에는 영향을 주지 않습니다. 이는 위치 대체 구현을 크게 단순화하면서 여유 공간에 따라 앵커 위치 박스를 이동해야 하는 근본적 요구를 충족합니다. 이러한 규칙은 저자(origin) 단계의 일반 선언을 오버라이드하므로, @position-try 선언이 일반적인 속성 계단(cascading) 및 상속과 부정적으로 상호작용하는 것도 제한해줍니다. 앞으로 컨테이너 쿼리의 확장으로 위치 대체 사용 여부를 기반으로 요소를 쿼리할 수 있게 되어, 이 제한된 속성 목록에서는 불가능한 조건부 스타일링도 가능해질 것으로 예상됩니다.
참고: 여러 박스가 서로 다른 앵커를 쓰면서 동일한 대체 위치를 사용하고 싶다면, <anchor-name>을 anchor()에서 생략하고 각 박스의 앵커는 position-anchor에 지정하면 됩니다.
참고: 가장 일반적인 대체 위치(앵커 한쪽에 박스를 두고, 필요시 반대편으로 뒤집는 등)는 position-try-fallbacks의 키워드만으로 @position-try 규칙 없이 자동으로 처리 가능합니다.
6.5. 위치 대체 적용
위치 지정 박스가 (기본 스크롤 이동량만큼 이동된 상태에서) inset-modified 포함 블록을 넘치고, 위치 옵션 목록이 비어 있지 않으면, 위치 대체 스타일 결정을 수행하여 오버플로우를 방지할 수 있는 옵션을 찾으려고 시도합니다.
이렇게 변경된 스타일은 인터리빙을 통해 요소에 적용되며, 계산값에 영향을 주고 (트랜지션 등도 트리거 가능), 레이아웃 및 사용값에 따라 달라집니다.
이 섹션을 더 명확하고 정확하게 다시 작성 필요. Issue 12818, Issue 12890 참고.
-
new styles를 위치 대체 origin에 cascade로 삽입 후, cascade를 해석하고, el의 사용값을 결정할 만큼 레이아웃을 수행합니다.
이 스타일 계산을 위해 가상의 앵커 재계산 시점을 계산하고, 결과 가상의 기억된 스크롤 오프셋을 사용하여 el의 스타일을 결정합니다.
-
el의 사용값을 반환합니다.
-
current styles를 abspos의 현재 사용값(이전 대체 적용 결과일 수 있음)으로 둡니다.
-
-
option이 현재 abspos의 마지막 성공 위치 옵션이면, 다음 반복.
-
위치 옵션 적용 option을 abspos에 적용한 결과를 adjusted styles로 둡니다.
-
el rect를 abspos의 마진 박스 크기 및 위치, cb rect를 abspos의 inset-modified 포함 블록의 크기 및 위치(해당 스타일 적용 시)로 둡니다.
-
cb rect가 어느 축에서든 음수 크기였다가 0으로 보정됐다면, 다음 반복.
참고: 이는 0 크기 el rect가 음수 크기 cb rect에 "들어있다"고 잘못 판단되는 것을 방지합니다.
-
el rect가 cb rect에 완전히 포함되지 않으면, 다음 반복.
-
adjusted styles를 가상으로 계산된 기억된 스크롤 오프셋과 함께 반환합니다.
-
-
이전 단계에서 오버플로우를 방지하는 위치 옵션을 찾지 못함을 단언합니다.
-
current styles를 반환합니다.
참고: el의 자손이 오버플로우해도 이 계산에 영향을 주지 않으며, el 자신의 마진 박스만 고려합니다.
참고: 현재 적용된 위치 옵션은 의도적으로 건너뛰므로, 해당 기억된 스크롤 오프셋이 업데이트되지 않습니다; 다른 대체가 모두 실패해 현재 스타일을 유지하면, 기억된 스크롤 오프셋도 그대로 유지됩니다.
전체 레이아웃 패스 중, 박스가 대체 스타일을 결정하면(혹은 대체 미사용 결정 시), 이후 배치되는 박스가 이 결정을 바꿀 수 없습니다.
즉, 레이아웃은 "뒤로 가지 않습니다".
ResizeObserver
이벤트가 결정되고 전달될 때:
-
요소 el이 마지막 성공 위치 옵션을 갖고 있으면, 다음 중 하나라도 해당하면 마지막 성공 위치 옵션을 제거합니다:
-
계산된 position 값이 변경되었거나, 포함 블록 연결이 변경되었거나, 더 이상 박스를 생성하지 않게 된 경우.
-
계산된 longhand position-try 값이 변경된 경우.
-
계산된 허용된 @position-try 속성 값이 변경된 경우.
-
참조 중인 @position-try 규칙이 추가/삭제/변경된 경우.
그 후, 위치 대체 스타일 결정을 el에 수행하고, 마지막 성공 위치 옵션을 현재 사용하는 허용된 @position-try 속성(값 포함)으로 설정합니다.
-
-
그 외의 경우, 박스 el이 절대 위치라면, 현재 사용하는 허용된 @position-try 속성(값 포함)을 마지막 성공 위치 옵션으로 설정합니다.
참고: 이 기록/제거 타이밍은 최종 기억 크기와 의도적으로 동일합니다.
구현체는 위치 옵션 목록 길이에 구현 정의 한도를 둘 수 있으며, 필요 이상 레이아웃 작업을 제한할 수 있습니다. 이 한도는 최소 5 이상이어야 합니다.
#myPopover{ position : fixed; top : anchor ( --button bottom); left : anchor ( --button left); position-try-fallbacks : flip-inline, flip-block, flip-block flip-inline; /* The popover is at least as wide as the button */ min-width:anchor-size ( --button width); /* The popover is at least as tall as 2 menu items */ min-height:6 em ; }
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 속성이 으로 계산됩니다.
표시 여부 체크 타이밍 정의 필요. [Issue #12732]
참고: 예를 들어 abspos가 DOM에서 앵커 옆에 있으면, 기본 앵커가 스크롤되어도 동일한 스크롤러에 의해 잘리므로 계속 보입니다.
clipped 정의가 View Transitions와 일치하는지 확인 필요, View Transitions도 비슷한 개념을 원함.
참고: “연쇄 앵커” 상황에서는, 첫 번째 abspos가 이 속성 때문에(앵커가 스크롤되어) 숨겨지면, 그걸 앵커로 쓰는 다음 abspos도 함께 숨겨져야 하며, 또 엉뚱한 위치에 떠 있으면 안 됩니다.
7. 접근성 영향
앵커 위치 지정은 위치 지정 박스와 그 앵커 사이에 자동으로 의미론적 관계를 설정하지 않는다는 점을 꼭 기억해야 합니다. 다양한 방식으로 활용될 수 있기 때문입니다. 작성자는 위치에 의해 암묵적으로 생기는 시각적 연결만으로 요소를 의미론적으로 연결하려 해서는 안 됩니다; 추가적인 조치 없이는 요소들이 의미 있는 DOM 관계가 없는 경우가 많아, 시각적이지 않은 사용자 에이전트(스크린 리더 등)에서는 사용이 어렵거나 불가능할 수 있습니다.
웹 플랫폼의 많은 기능(기존 기능 및 신규 기능)들은 이런 연결을 명시적으로 설정할 수 있게 해주며, 비시각적 사용자 에이전트도 혜택을 볼 수 있습니다.
예를 들어 HTML의 Popover API는 인보커 버튼과 팝오버 요소를 자동으로 연결하며, 탭 순서도 자동 조정합니다; 또한 인보커 버튼을 팝오버의 암시적 앵커 요소로 지정해 앵커 위치 지정도 쉽게 활용할 수 있게 해줍니다.
좀 더 일반적인 경우엔,
ARIA의 aria-details
또는 aria-describedby
속성을
앵커 요소에 사용해
정보를 보다 수동적으로 제공할 수 있습니다;
위치 지정 요소에는
role
속성을 함께 사용하면,
비시각적 사용자 에이전트가
요소들 간의 관계를 사용자에게 알려주고 자동으로 이동할 수 있게 해줍니다.
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년 5월 9일자 Working Draft 이후 주요 변경점:
-
x/y-self-start/end 키워드를 self-x/y-start/end로 변경 (position-area에서 순서 혼동이 지속됨) (이슈 12749)
-
position-area가 박스의 포함 블록이 스크롤 컨테이너일 때 (새로 정의된) 스크롤 가능한 포함 블록을 사용하도록 수정 (이슈 10861)
-
단일 position-area 축의 auto inset에서 기본 정렬이 non-auto 쪽으로 정렬되도록 수정 (이슈 12512)
-
dialog 값을 align-self와 justify-self에 추가 (HTML 팝오버의 기본 UA 스타일시트 규칙 문제 해결) (이슈 10258)
-
마지막 성공 위치 옵션이 언제 지워지는지 명확화 (이슈 12577)
-
anchor-scope와 position-anchor에서 트리 범위 이름 앵커 매칭 방법 명확화 (이슈 7916, 9408, 5984)
-
top layer가 허용 가능한 앵커 요소 찾기와 어떻게 상호작용하는지 명확히 하고, 유효한 앵커 규칙을 더 쉽게 이해하도록 재작성 (이슈 11602)
-
position-try-fallbacks의 문법에서 none 키워드 목록을 제외하도록 수정 (이슈 12838)
-
여러 가지 작은 수정 및 명확화 (이슈 11028, 이슈 11080, 이슈 12058, 이슈 12636, 이슈 12653, 이슈 12732)
이전 변경 사항은 이전 변경 내역도 참고하세요.