1. 소개
이 섹션은 규범적이지 않습니다.
반응형 웹 컴포넌트는 Element
의
크기 변화에 대응해야 합니다. 예를 들어, 지도를 표시하는 Element
가
있습니다:
-
지도는 자신의 content box를
Element
타일로 채워서 표시합니다. -
크기가 변경되면 타일링을 다시 해야 합니다.
반응형 웹 애플리케이션은 이미 viewport 크기 변화에 대응할 수 있습니다.
이는 CSS 미디어 쿼리나 window.resize
이벤트로 구현됩니다.
ResizeObserver API는 Element의 크기 변화를 관찰하는 인터페이스입니다. 이것은 window.resize
이벤트에 대응하는 Element
의
기능입니다.
ResizeObserver의 알림은 Element
크기 변화에 대응하는 데 사용할 수 있습니다. 이 관찰에 관한 몇 가지 흥미로운 사실:
-
관찰 대상인 Element가 DOM에 삽입/제거될 때 관찰이 실행됩니다.
-
관찰 대상 Element의 display 속성이 none으로 설정될 때 관찰이 실행됩니다.
-
치환되지 않은 인라인 Element에는 관찰이 실행되지 않습니다.
-
CSS transform에 의해 관찰이 실행되지 않습니다.
-
관찰이 시작될 때 Element가 렌더링 중이고 Element의 크기가 0,0이 아니면 관찰이 실행됩니다.
< canvas id = "elipse" style = "display:block" ></ canvas > < div id = "menu" style = "display:block;width:100px" > < img src = "hamburger.jpg" style = "width:24px;height:24px" > < p class = "title" > menu title</ p > </ div >
// 크기 변경에 따라, elipse는 캔버스 안에 타원을 그림 document. querySelector( '#elipse' ). handleResize= entry=> { entry. target. width= entry. borderBoxSize[ 0 ]. inlineSize; entry. target. height= entry. borderBoxSize[ 0 ]. blockSize; let rx= Math. floor( entry. target. width/ 2 ); let ry= Math. floor( entry. target. height/ 2 ); let ctx= entry. target. getContext( '2d' ); ctx. beginPath(); ctx. ellipse( rx, ry, rx, ry, 0 , 0 , 2 * Math. PI); ctx. stroke(); } // 크기 변경에 따라, width에 따라 title의 표시 여부 변경 document. querySelector( '#menu' ). handleResize= entry=> { let title= entry. target. querySelector( ".title" ) if ( entry. borderBoxSize[ 0 ]. inlineSize< 40 ) title. style. display= "none" ; else title. style. display= "inline-block" ; } var ro= new ResizeObserver( entries=> { for ( let entryof entries) { let cs= window. getComputedStyle( entry. target); console. log( 'watching element:' , entry. target); console. log( entry. contentRect. top, ' is ' , cs. paddingTop); console. log( entry. contentRect. left, ' is ' , cs. paddingLeft); console. log( entry. borderBoxSize[ 0 ]. inlineSize, ' is ' , cs. width); console. log( entry. borderBoxSize[ 0 ]. blockSize, ' is ' , cs. height); if ( entry. target. handleResize) entry. target. handleResize( entry); } }); ro. observe( document. querySelector( '#elipse' )); ro. observe( document. querySelector( '#menu' ));
2. 크기 관찰자 API
2.1. ResizeObserver 인터페이스
ResizeObserver 인터페이스는 Element
의
크기 변화를 관찰하는 데 사용됩니다.
이는 MutationObserver
및 IntersectionObserver
를
기반으로 모델링되었습니다.
enum {
ResizeObserverBoxOptions ,
"border-box" ,
"content-box" };
"device-pixel-content-box"
ResizeObserver는 다양한 종류의 CSS 크기를 관찰할 수 있습니다:
-
border-box
: CSS2에서 정의된 박스 border 영역의 크기입니다. -
content-box
: CSS2에서 정의된 content 영역의 크기입니다. -
device-pixel-content-box
: CSS2에서 정의된 content 영역의 크기를 디바이스 픽셀 단위로, 해당 요소나 조상에 적용된 CSS transform 이전의 크기입니다. 이 크기는 반드시 정수 값이어야 합니다.
device-pixel-content-box
는 devicePixelRatio와 content-box
크기를 곱하여 근사할 수 있습니다.
하지만 브라우저별 서브픽셀 스냅 동작 때문에,
저자(개발자)는 이 스케일된 content-box
크기의 올바른 반올림 방법을 결정할 수 없습니다.
UA가 요소의 디바이스 픽셀 박스를 계산하는 방법은 구현에 따라 다릅니다.
한 가지 가능한 구현은 박스 크기와 위치에 device pixel ratio를 곱한 후,
얻어진 부동소수점 크기와 위치를 모두 정수로 반올림하는 것이며,
이 때 렌더링 결과의 품질을 최대화하는 방식으로 처리할 수 있습니다.
이 크기는 대상의 위치 변화에 의해 영향을 받을 수 있으므로, 다른 크기보다 관찰 비용이 더 높을 수 있습니다.
dictionary {
ResizeObserverOptions ResizeObserverBoxOptions = "content-box"; };
box
이 섹션은 규범적이지 않습니다. 저자가 여러 CSS 박스를 관찰하고 싶을 경우, 여러 개의 ResizeObserver를 사용해야 합니다.
// content-box를 관찰 ro. observe( document. querySelector( '#menu' ), { box: 'content-box' }); // border box만 관찰. 이전 관찰을 대체함. ro1. observe( document. querySelector( '#menu' ), { box: 'border-box' });
이 설정은 이벤트가 발생할 때 정의된 콜백에 어떤 박스 크기가 반환되는지에는 영향을 미치지 않으며, 저자가 레이아웃 변화 관찰을 원하는 박스를 지정하는 데만 사용됩니다.
[Exposed =(Window ),Constructor (ResizeObserverCallback )]
callback interface {
ResizeObserver void observe (Element ,
target optional ResizeObserverOptions );
options void unobserve (Element );
target void disconnect (); };
new ResizeObserver(callback)
-
-
this를 새로운
ResizeObserver
객체로 생성합니다. -
this.callback 내부 슬롯을 callback으로 설정합니다.
-
this.observationTargets 내부 슬롯을 빈 리스트로 설정합니다.
-
this를
Document
.resizeObservers 슬롯에 추가합니다.
-
observe(target, options)
-
target을 관찰 대상 요소 리스트에 추가합니다.
-
target이
observationTargets
슬롯에 이미 있다면, unobserve(target)을 호출합니다. -
resizeObservation을 새로운
ResizeObservation
(target, options)으로 생성합니다. -
resizeObservation을 observationTargets 슬롯에 추가합니다.
-
unobserve(target)
-
target을 관찰 대상 요소 리스트에서 제거합니다.
-
observation을
ResizeObservation
중observationTargets
의 target 슬롯이 target인 것으로 찾습니다. -
observation이 없다면, 반환합니다.
-
observation을
observationTargets
에서 제거합니다.
-
disconnect()
-
-
observationTargets
리스트를 비웁니다. -
activeTargets
리스트를 비웁니다.
-
2.2. ResizeObserverCallback
callback =
ResizeObserverCallback void (sequence <ResizeObserverEntry >,
entries ResizeObserver );
observer
이 콜백은 ResizeObserver
의
알림을 전달합니다. 활성 관찰 브로드캐스트 알고리즘에 의해 호출됩니다.
2.3. ResizeObserverEntry
[Exposed =Window ]interface {
ResizeObserverEntry readonly attribute Element target ;readonly attribute DOMRectReadOnly contentRect ;readonly attribute sequence <ResizeObserverSize >borderBoxSize ;readonly attribute sequence <ResizeObserverSize >contentBoxSize ;readonly attribute sequence <ResizeObserverSize >devicePixelContentBoxSize ; };
contentRect는 ResizeObserver의 인큐베이팅 단계에서 도입되었으며, 현재 웹 호환성 유지를 위해 포함되어 있습니다. 향후 레벨에서 폐지될 수 있습니다.
target
, 타입 Element, 읽기 전용-
크기가 변경된
Element
입니다. contentRect
, 타입 DOMRectReadOnly, 읽기 전용-
Element
의 content rect로,ResizeObserverCallback
이 호출될 때의 값입니다. borderBoxSize
, 타입 sequence<ResizeObserverSize>, 읽기 전용-
시퀀스에
Element
의 border box 크기가 담겨 있으며,ResizeObserverCallback
이 호출될 때의 값입니다. contentBoxSize
, 타입 sequence<ResizeObserverSize>, 읽기 전용-
시퀀스에
Element
의 content rect 크기가 담겨 있으며,ResizeObserverCallback
이 호출될 때의 값입니다. devicePixelContentBoxSize
, 타입 sequence<ResizeObserverSize>, 읽기 전용-
시퀀스에
Element
의 content rect가 정수형 디바이스 픽셀 단위로 담겨 있으며,ResizeObserverCallback
이 호출될 때의 값입니다.
박스 크기 속성들은 여러 fragment를 가질 수 있는 요소를 지원하기 위해 시퀀스로 노출됩니다. 이는 멀티 컬럼 시나리오에서 발생합니다. 하지만 content rect와 border box의 현행 정의에서는 멀티 컬럼 레이아웃에 의해 박스가 어떻게 영향을 받는지 언급되지 않습니다. 이 명세에서는 시퀀스에 단일 ResizeObserverSize만 반환되며, 이는 첫 번째 컬럼의 크기에 해당합니다. 이후 버전의 명세에서는 시퀀스에 fragment별 크기 정보를 포함하도록 확장될 예정입니다.
interface {
ResizeObserverSize readonly attribute unrestricted double ;
inlineSize readonly attribute unrestricted double ; };
blockSize
3. 처리 모델
3.1. ResizeObservation 예시 구조체
이 섹션은 규범적이지 않습니다. ResizeObservation은 Resize Observer 구현 시 사용할 수 있는 예시 구조체입니다.
처리 모델 설명을 명확히 하기 위해 포함된 것으로, 단일 Element
의
관찰 정보를 효과적으로 담고 있습니다.
이 인터페이스는 Javascript에서 볼 수 없습니다.
[(
Constructor Element ) ]
target interface {
ResizeObservation readonly attribute Element target ;readonly attribute ResizeObserverBoxOptions observedBox ;readonly attribute sequence <ResizeObserverSize >lastReportedSizes ; };
target
, 타입 Element, 읽기 전용-
관찰 중인
Element
입니다. observedBox
, 타입 ResizeObserverBoxOptions, 읽기 전용-
관찰 중인 박스 종류입니다.
lastReportedSizes
, 타입 sequence<ResizeObserverSize>, 읽기 전용-
마지막으로 보고된 크기들의 순서 있는 시퀀스입니다.
new ResizeObservation(target, observedBox)
-
-
this를 새로운
ResizeObservation
객체로 생성합니다. -
this 내부
target
슬롯을 target으로 설정합니다. -
this 내부
observedBox
슬롯을 observedBox로 설정합니다. -
this 내부
lastReportedSizes
슬롯을 [(0,0)]으로 설정합니다.
-
isActive()
-
-
currentSize를 박스 크기 계산 알고리즘을 통해 target과 observedBox로부터 구합니다.
-
currentSize가 this.
lastReportedSizes
의 첫 번째 항목과 다르면 true를 반환합니다. -
false를 반환합니다.
-
3.2. 내부 슬롯 정의
3.2.1. Document
Document는 resizeObservers
슬롯을 가지며, 이 슬롯은 이 문서에서의 ResizeObserver
목록입니다. 초기값은 빈 리스트입니다.
3.2.2. ResizeObserver
ResizeObserver
는 callback
슬롯을 가지며, 생성자에서 초기화됩니다.
ResizeObserver
는 observationTargets
슬롯을 가지며,
이 슬롯은 ResizeObservation
목록입니다.
관찰 중인 모든 Element를 나타냅니다.
ResizeObserver
는 activeTargets
슬롯을 가지며,
이 슬롯은 ResizeObservation
목록입니다.
마지막 관찰 브로드캐스트 이후 크기가 변경되어 브로드캐스트 대상이 되는 모든 Element를 나타냅니다.
ResizeObserver
는 skippedTargets
슬롯을 가지며,
이 슬롯은 ResizeObservation
목록입니다.
마지막 관찰 브로드캐스트 이후 크기가 변경되었으나 브로드캐스트 대상이 **아닌** 모든 Element를 나타냅니다.
3.3. CSS 정의
3.3.1. content rect
DOM content rect는 다음과 같은 rect입니다:-
width는 content width
-
height는 content height
-
top은 padding top
-
left는 padding left
content width 명세는 멀티 컬럼 레이아웃이 content box에 미치는 영향을 언급하지 않습니다. 본 명세에서는,
multi-column 내부 Element
의
content width는 getComputedStyle(element).width
의 결과입니다. 현재는 첫 번째 컬럼의 너비로 평가됩니다.
content rect 위치가 padding-top/left인 것은 대상 자식의 절대 위치 지정에 유용합니다. 절대 위치 좌표 공간의 원점은 padding rect의 좌상단입니다.
content rect를 관찰하면 다음과 같은 동작이 발생합니다:
-
관찰 대상 Element가 DOM에 삽입/제거될 때 관찰이 실행됩니다.
-
관찰 대상 Element의 display가 none으로 설정될 때 관찰이 실행됩니다.
-
치환되지 않은 인라인 Element는 항상 빈 content rect를 가집니다.
-
CSS transform에 의해 관찰이 실행되지 않습니다.
웹 콘텐츠에는 SVG 요소도 포함될 수 있습니다. SVG Element는 content box 대신 bounding box를 정의합니다. SVGGraphicsElement의 content rect는 다음과 같은 rect입니다:
-
width는 bounding box width
-
height는 bounding box height
-
top과 left는 0
3.4. 알고리즘
3.4.1. 깊이에서 활성 관찰 모으기
이 알고리즘은 document의 모든 활성 관찰을 계산합니다. 깊이에서 활성 관찰 모으기를 위해 다음 단계를 실행합니다:
-
전달받은 depth를 설정합니다.
-
resizeObservers
의 각 observer에 대해 다음 단계를 실행합니다:-
observer의
activeTargets
와skippedTargets
를 모두 비웁니다. -
observer.
observationTargets
의 각 observation에 대해 다음 단계를 실행합니다:-
observation.
isActive()
가 true이면-
targetDepth가 depth보다 크면 observation을
activeTargets
에 추가합니다. -
그 외의 경우 observation을
skippedTargets
에 추가합니다.
-
-
3.4.2. 활성 관찰 있음
Document
에
활성 관찰 있음을
판단하려면 다음 단계를 실행합니다:
-
resizeObservers
의 각 observer에 대해 다음 단계를 실행합니다:-
observer.
activeTargets
가 비어있지 않으면 true를 반환합니다.
-
-
false를 반환합니다.
3.4.3. 건너뛴 관찰 있음
Document
에
건너뛴 관찰 있음을
판단하려면 다음 단계를 실행합니다:
-
resizeObservers
의 각 observer에 대해 다음 단계를 실행합니다:-
observer.
skippedTargets
가 비어있지 않으면 true를 반환합니다.
-
-
false를 반환합니다.
3.4.4. ResizeObserverEntry 생성 및 채우기
ResizeObserverEntry 생성 및 채우기를 target에 대해 실행하려면, 다음 단계를 따르세요:-
this를 새로운
ResizeObserverEntry
로 설정합니다. -
this.
target
슬롯을 target으로 설정합니다. -
this.
borderBoxSize
슬롯을 target과 "border-box" observedBox로 크기 계산 결과로 설정합니다. -
this.
contentBoxSize
슬롯을 target과 "content-box" observedBox로 크기 계산 결과로 설정합니다. -
this.
devicePixelContentBoxSize
슬롯을 target과 "device-pixel-content-box" observedBox로 크기 계산 결과로 설정합니다. -
this.
contentRect
를 논리적 this.contentBoxSize
로, target과 "content-box" observedBox로 설정합니다. -
target이 SVG 요소가 아니라면 다음 단계를 실행하세요:
-
this.contentRect.top을 target.padding top으로 설정합니다.
-
this.contentRect.left를 target.padding left로 설정합니다.
-
-
target이 SVG 요소라면 다음 단계를 실행하세요:
-
this.contentRect.top과 this.contentRect.left를 0으로 설정합니다.
-
3.4.5. 활성 관찰 알림 브로드캐스트
활성 관찰 브로드캐스트는 문서의 모든 활성 관찰을 전달하며, 브로드캐스트된 대상 중 가장 얕은 깊이를 반환합니다.
document에 대해 활성 관찰을 브로드캐스트하려면, 다음 단계를 따르세요:
-
shallowestTargetDepth를 ∞로 설정합니다.
-
document.
resizeObservers
의 각 observer에 대해 다음 단계를 실행하세요:-
observer.
activeTargets
슬롯이 비어 있으면 계속 진행합니다. -
entries를
ResizeObserverEntry
의 빈 리스트로 설정합니다. -
activeTargets
의 각 observation에 대해 다음 단계를 실행하세요:-
entry를 ResizeObserverEntry 생성 및 채우기를 observation.
target
에 대해 실행한 결과로 설정합니다. -
entry를 entries에 추가합니다.
-
observation.
lastReportedSizes
를 일치하는 entry 크기로 설정합니다.-
일치하는 크기가 observation.
observedBox
가 "border-box"일 때 entry.borderBoxSize
입니다. -
일치하는 크기가 observation.
observedBox
가 "content-box"일 때 entry.contentBoxSize
입니다. -
일치하는 크기가 observation.
observedBox
가 "device-pixel-content-box"일 때 entry.devicePixelContentBoxSize
입니다.
-
-
targetDepth를 노드의 깊이 계산을 observation.
target
에 대해 실행한 결과로 설정합니다. -
targetDepth가 shallowestTargetDepth보다 작으면 shallowestTargetDepth를 targetDepth로 설정합니다.
-
-
observer.
callback
을 entries로 호출합니다. -
observer.
activeTargets
를 비웁니다.
-
-
shallowestTargetDepth를 반환합니다.
3.4.6. Resize Loop 오류 전달
Resize Loop 오류 알림 전달을 실행하려면 다음 단계를 따르세요:
-
새
ErrorEvent
를 생성합니다. -
event의 message 슬롯을 "ResizeObserver loop completed with undelivered notifications."로 초기화합니다.
-
예외 event를 보고합니다.
3.4.7. 노드의 깊이 계산
노드의 깊이 계산을 node에 대해 실행하려면, 다음 단계를 따르세요:
-
p를 node에서 이 요소의 평탄화된 DOM 트리의 루트 Element까지의 부모-트래버설 경로로 설정합니다.
-
p의 노드 개수를 반환합니다.
3.4.8. 대상 및 관찰 박스 기준 박스 크기 계산
이 알고리즘은 target Element
의
관찰 박스 크기를 계산합니다. 박스 타입은
ResizeObserverBoxOptions
로
설명됩니다.
SVG 요소는 예외입니다. SVG 크기는 항상 bounding box 크기이며, SVG 요소는 표준 CSS 박스 모델을 사용하지 않습니다.
박스 크기 계산을 target 및 observedBox에 대해 실행하려면, 다음 단계를 따르세요:
-
target이
SVGGraphicsElement
라면-
computedSize.inlineSize를 target의 bounding box 인라인 길이로 설정합니다.
-
computedSize.blockSize를 target의 bounding box 블록 길이로 설정합니다.
-
-
target이
SVGGraphicsElement
가 아니라면-
observedBox가 "border-box"라면
-
computedSize.inlineSize를 target의 border area 인라인 길이로 설정합니다.
-
computedSize.blockSize를 target의 border area 블록 길이로 설정합니다.
-
-
observedBox가 "content-box"라면
-
computedSize.inlineSize를 target의 content area 인라인 길이로 설정합니다.
-
computedSize.blockSize를 target의 content area 블록 길이로 설정합니다.
-
-
observedBox가 "device-pixel-content-box"라면
-
computedSize.inlineSize를 target의 content area 인라인 길이(정수형 디바이스 픽셀)로 설정합니다.
-
computedSize.blockSize를 target의 content area 블록 길이(정수형 디바이스 픽셀)로 설정합니다.
-
-
computedSize를 반환합니다.
-
3.5. ResizeObserver 생명주기
ResizeObserver
는 다음 두 조건이 모두 충족될 때까지 살아 있습니다:
-
관찰자에 대한 스크립팅 참조가 없는 경우.
-
관찰자가 어떤 대상을 관찰하고 있지 않은 경우.
3.6. 외부 명세 통합
3.6.1. HTML 처리 모델: 이벤트 루프
ResizeObserver
처리는 HTML 처리 모델 이벤트 루프의 7.12단계에서 수행됩니다.
12단계는 현재 다음과 같이 명확히 정의되어 있지 않습니다:
docs의 모든 완전히 활성화된 Document에 대해, 해당 Document와 그 브라우징 컨텍스트의 렌더링 또는 사용자 인터페이스를 현재 상태에 맞게 갱신한다.
.
기존 12단계는 다음과 같이 완전히 명세될 수 있습니다:
docs의 모든 완전히 활성화된 Document에 대해, 해당 Document와 그 브라우징 컨텐츠에 대해 다음 단계를 실행:
-
스타일 재계산
-
레이아웃 업데이트
-
페인트
ResizeObserver
는 12단계에 리사이즈 알림 처리를 확장합니다.
모든 보류 중인 알림을 처리하기 위해,
더 이상 보류 중인 알림이 없을 때까지 루프를 반복합니다. 이 과정에서
무한 루프가 발생할 수 있습니다.
무한 루프는 각 반복마다 알림 가능한 노드 집합을 축소함으로써 방지됩니다. 각 반복에서는 이전 반복에서 가장 얕았던 노드보다 더 깊은 노드만 알림이 가능합니다.
알림 루프가 완료되고 아직 전달되지 않은 알림이 있을 경우 오류가 발생합니다. 전달되지 않은 알림이 있는 요소는 다음 루프에서 다시 전달 대상으로 고려됩니다.
ResizeObserver 알림이 포함된 12단계는 다음과 같습니다:
docs의 모든 완전히 활성화된 Document에 대해, 해당 Document와 그 브라우징 컨텍스트에 대해 다음 단계를 실행:
-
스타일 재계산
-
레이아웃 업데이트
-
depth를 0으로 설정
-
깊이에서 활성 관찰 모으기 depth를
Document
에 대해 실행 -
document에 활성 관찰 있음 동안 반복
-
depth를 활성 관찰 브로드캐스트 결과로 설정
-
스타일 재계산
-
레이아웃 업데이트
-
깊이에서 활성 관찰 모으기 depth를
Document
에 대해 실행
-
-
Document
와 그 브라우징 컨텍스트의 렌더링 또는 UI를 현재 상태에 맞게 갱신