1. 소개
웹의 기존 위치 계산 메커니즘은 DOM 상태에 대한 명시적 쿼리에 의존합니다. 이는 (비싼) 스타일 재계산 및 레이아웃을 유발하는 것으로 알려져 있으며, 자주 이 정보를 지속적으로 폴링하기 때문에 상당한 성능 오버헤드의 원인이 됩니다.
이러한 동작에 의존하는 일반적인 사례들이 발전해 왔으며, 예를 들면 다음과 같습니다:
-
DOM 및 데이터의 사용자 정의 사전 로딩 및 지연 로딩 구현.
-
데이터에 바인딩된 고성능 스크롤 리스트 구현(데이터 집합의 일부만 로드 및 렌더링). 이러한 리스트는 모바일 상호작용의 핵심 방식입니다.
-
요소의 가시성 계산. 특히, 광고 네트워크는 이제 광고 "시청 가능성" 보고를 요구하며 이를 통해 노출에 대한 수익을 창출합니다. 이로 인해 많은 사이트들이 스크롤 핸들러를 남용(스크롤 시 끊김 발생), 동기 레이아웃 및 리드백 호출(rAF 루프 내에 불필요한 작업 발생), 그리고 "진짜" 요소 가시성 계산을 위해 특이한 플러그인 기반 솔루션을 사용하는 상황(플러그인 구조의 오버헤드 포함)이 생겼습니다.
이러한 사용 사례들은 몇 가지 공통적인 특성을 가집니다:
-
개별 요소의 상태에 대한 수동적 "쿼리"로 표현될 수 있습니다. 이는 다른 요소(또는 글로벌 뷰포트)에 대한 것입니다.
-
엄격한 지연 시간 요구사항이 없습니다. 즉, 정보가 비동기적으로(예: 다른 스레드에서) 전달되어도 문제가 없습니다.
-
대부분의 기존 웹 플랫폼 기능 조합에서 지원이 미흡하여, 광범위하게 사용됨에도 불구하고 개발자가 상당한 노력을 들여야 합니다.
주목할 만한 비목표는 실제로 표시된 픽셀 단위의 정확한 정보입니다. 이는 필터, webgl, 기타 기능이 있는 특정 브라우저 구조에서는 효율적으로 얻기 어렵기 때문입니다. 이러한 모든 상황에서 약간의 지연이 있더라도, 완벽한 합성 결과 데이터가 없어도 정보는 유용합니다.
Intersection Observer API는 위의 문제들을 해결하기 위해, 개발자가 요소의 위치를 다른 요소 또는 글로벌 뷰포트에 대해 비동기적으로 쿼리할 수 있는 새로운 방법을 제공합니다. 비동기 전달 방식으로 인해 비용이 많이 드는 DOM 및 스타일 쿼리, 지속적인 폴링, 커스텀 플러그인 사용이 필요 없어집니다. 이러한 방법들이 불필요해짐에 따라 애플리케이션은 CPU, GPU, 에너지 비용을 크게 줄일 수 있습니다.
var observer= new IntersectionObserver( changes=> { for ( const changeof changes) { console. log( change. time); // 변경이 발생한 타임스탬프 console. log( change. rootBounds); // 루트의 잘리지 않은 영역 console. log( change. boundingClientRect); // target.getBoundingClientRect() console. log( change. intersectionRect); // boundingClientRect, 포함 블록 조상에 의해 잘리고, rootBounds와 교차된 영역 console. log( change. intersectionRatio); // intersectionRect 영역과 boundingClientRect 영역의 비율 console. log( change. target); // 대상 요소(Element) } }, {}); // 특정 대상 요소(Element)에 대한 교차 이벤트 감시. observer. observe( target); // 특정 대상 요소(Element)에 대한 교차 이벤트 감시 중지. observer. unobserve( target); // 모든 대상 요소에 대한 임계값 이벤트 감시 중지. observer. disconnect();
2. 교차 관찰자
Intersection Observer API는 개발자가 대상 DOM 요소가 교차 루트에 대해 얼마나 보이는지와 위치를 이해할 수 있도록 해줍니다.
2.1. IntersectionObserverCallback
callback =
IntersectionObserverCallback undefined (sequence <IntersectionObserverEntry >,
entries IntersectionObserver );
observer
이 콜백은 대상과 교차 루트의 교차에 변경이 있을 때 처리 모델에 따라 호출됩니다.
2.2. IntersectionObserver 인터페이스
IntersectionObserver
인터페이스는 교차 루트와 하나 이상의 대상 Element
의
교차 변화를 관찰하는 데 사용할 수 있습니다.
교차 루트는 IntersectionObserver
의
root
속성 값이며,
이 속성이 null
이 아닌 경우 그 값을 사용하고,
그렇지 않으면 최상위 브라우징 컨텍스트의 document
노드가 됩니다. 이 경우 암시적 루트라고 합니다.
IntersectionObserver
에서
null
이 아닌 root
를 가지면 명시적 루트 관찰자라고 하며,
대상
Element
가 포함 블록 체인에서 root
의
자손이면 모두 관찰할 수 있습니다.
IntersectionObserver
에서
null
root
를 가지면 암시적 루트 관찰자라고 합니다.
암시적 루트 관찰자의 유효한 대상에는 Element
가 최상위 브라우징 컨텍스트에 있거나,
중첩 브라우징 컨텍스트에 있는 Element도 포함됩니다.
암시적 루트 관찰자의 경우, API는 대상의 관련 설정 객체의 origin이 동일 오리진 도메인인지 여부에 따라 동일 오리진 도메인 대상과 교차 오리진 도메인 대상을 구분합니다. 명시적 루트 관찰자의 모든 대상은 동일 오리진 도메인 대상입니다. 대상이 교차 루트와 동일한 document에 있기 때문입니다.
참고: MutationObserver
에서는
MutationObserverInit
옵션을
observe()
에
전달하지만,
IntersectionObserver
에서는
생성자에 전달합니다. MutationObserver에서는 각 Node
마다 필터링할 속성 집합이 다를 수 있기 때문입니다. IntersectionObserver에서는 하나의 관찰자를 여러 대상에 동일한 옵션으로 사용하거나, 각 대상마다 다른 관찰자를 사용할 수
있습니다.
rootMargin
이나
threshold
값을
각 대상마다 다르게 지정하는 것은 복잡성만 높이고 추가적인 사용 사례를 해결하지 못하기 때문에, 필요하다면
추후에 observe() 별 옵션이 추가될 수 있습니다.
[Exposed =Window ]interface {
IntersectionObserver (
constructor IntersectionObserverCallback ,
callback optional IntersectionObserverInit = {});
options readonly attribute (Element or Document )?root ;readonly attribute DOMString rootMargin ;readonly attribute DOMString scrollMargin ;readonly attribute FrozenArray <double >thresholds ;undefined observe (Element );
target undefined unobserve (Element );
target undefined disconnect ();sequence <IntersectionObserverEntry >takeRecords (); };
new IntersectionObserver(callback, options)
-
callback과 options를 제공하여 새 IntersectionObserver 초기화 알고리즘을 실행한 결과를 반환합니다.
observe(target)
-
this와 target을 제공하여 대상 요소 관찰 알고리즘을 실행합니다.
unobserve(target)
-
this와 target을 제공하여 대상 요소 관찰 중지 알고리즘을 실행합니다.
참고:
MutationObserver
는unobserve()
를 구현하지 않습니다. IntersectionObserver에서는unobserve()
가 지연 로딩(lazy-loading) 사용 사례를 해결합니다. target이 보이게 된 후에는 더 이상 추적할 필요가 없습니다. 모든 target을disconnect()
하고 남은 것만observe()
하거나, 각 target마다 별도의IntersectionObserver
를 만드는 것이 더 번거롭습니다. disconnect()
-
this의 내부
[[ObservationTargets]]
슬롯에 있는 각 target에 대해:-
target의 내부
[[RegisteredIntersectionObservers]]
슬롯에서IntersectionObserverRegistration
레코드 중observer
속성이 this와 같은 것을 제거합니다. -
this의 내부
[[ObservationTargets]]
슬롯에서 target을 제거합니다.
-
takeRecords()
-
-
this의 내부
[[QueuedEntries]]
슬롯의 복사본을 queue로 둡니다. -
this의 내부
[[QueuedEntries]]
슬롯을 비웁니다. -
queue를 반환합니다.
-
root
, 타입(Element or Document)
, readonly, nullable-
root
는IntersectionObserver
생성자에 전달된 값이며, 전달되지 않은 경우null
입니다. rootMargin
, 타입 DOMString, readonly-
루트 교차 사각형에 적용되는 오프셋으로, 교차 계산에 사용되는 박스를 확장하거나 축소합니다. 이 오프셋은 동일 오리진 도메인 대상에만 적용되며, 교차 오리진 도메인 대상에는 무시됩니다.
값을 얻을 때,
[[rootMargin]]
요소를 공백으로 구분해 직렬화하여 반환합니다. 픽셀 단위는 숫자 뒤에 "px"가 붙고, 퍼센트는 숫자 뒤에 "%"가 붙습니다. 이 값은 options.rootMargin
으로 생성자에 전달된 것과 동일함을 보장하지 않습니다. 아무 값도 전달되지 않은 경우 "0px 0px 0px 0px"입니다. scrollMargin
, 타입 DOMString, readonly-
scrollport에서 교차 루트에서 대상까지의 경로에 있는 모든 스크롤 가능한 조상에 오프셋이 적용되어, 교차 계산에 사용되는 클립 영역을 확장 또는 축소합니다.
값을 얻을 때,
[[scrollMargin]]
요소를 공백으로 구분해 직렬화하여 반환합니다. 픽셀 단위는 "px"가, 퍼센트는 "%"가 붙습니다. 이 값은 options.scrollMargin
으로 생성자에 전달된 것과 동일함을 보장하지 않습니다. 값이 없다면 "0px 0px 0px 0px"입니다. thresholds
, 타입 FrozenArray<double>, readonly-
임계값의 리스트로, 오름차순으로 정렬된 숫자이며, 각각의 임계값은 관찰 대상의 교차 영역과 바운딩 박스 영역의 비율입니다. 대상의 임계값이 변경될 때 알림이 발생합니다. options.
threshold
가 제공되지 않거나 시퀀스가 비어 있으면 이 속성 값은 [0]입니다.
Element
는, 계산된 스타일에 overflow 속성이 있어 요소의 패딩 엣지로 내용을 클립할 경우
콘텐츠 클립을 가진 것으로 정의합니다.
루트 교차 사각형은 IntersectionObserver
에서 대상과 비교할 때 사용하는 사각형입니다.
- 만약
IntersectionObserver
가 암시적 루트 관찰자라면, - 루트가 최상위 브라우징 컨텍스트의
document
인 것처럼 처리합니다. - 만약 교차 루트가
document
라면, document
의 뷰포트 크기(이 단계는document
가 완전히 활성화된 경우에만 해당)- 그 외에 교차 루트가 콘텐츠 클립을 가진다면,
- 요소의 패딩 영역이 됩니다.
- 그 외의 경우,
- 요소의 바운딩 박스 구하기 결과가 교차 루트가 됩니다.
루트 교차 사각형을 동일 오리진 도메인 대상에 대해 계산할 때,
IntersectionObserver
의
[[rootMargin]]
슬롯에 있는 오프셋에 따라 CSS의 margin 속성처럼
네 값이 각각 위, 오른쪽, 아래, 왼쪽 변이 얼마나 오프셋되는지 나타내며,
양수 길이는 바깥쪽으로 오프셋이 됨을 의미합니다.
퍼센트는 확장되지 않은 사각형의 너비를 기준으로 해석됩니다.
참고: rootMargin
은 교차 루트에만 적용됩니다.
대상
Element
가 교차 루트가 아닌 조상에 의해 클립될 경우, 해당 클립에는 rootMargin
이
영향을 주지 않습니다.
- 스크롤포트에 scroll margin을 적용하다
-
스크롤포트 교차 사각형을 동일 출처 도메인 대상에 대해 계산할 때, 사각형은
IntersectionObserver
의[[scrollMargin]]
슬롯에 있는 오프셋에 따라 확장됩니다. 이는 CSS의 margin 속성과 유사하게 동작하며, 네 개의 값은 각각 위, 오른쪽, 아래, 왼쪽 가장자리의 오프셋 크기를 나타냅니다. 양수 길이는 바깥쪽으로 오프셋됨을 의미합니다. 백분율은 확장되지 않은 사각형의 너비를 기준으로 해석됩니다.이 오프셋은 동일 출처 도메인 대상을 처리할 때에만 적용되며, 교차 출처 도메인 대상에는 무시됩니다.
참고:
scrollMargin
은 대상이 모든 스크롤 가능한 조상(교차 루트 포함)에 의해 잘릴 때 영향을 줍니다.scrollMargin
과rootMargin
은 스크롤 가능한 교차 루트 사각형에도 적용됩니다.
참고: 루트 교차 사각형과 스크롤포트 교차 사각형은 핀치 줌의 영향을 받지 않으며 조정되지 않은 뷰포트를 보고합니다. 이는 핀치 줌의 의도(돋보기처럼 동작하며 레이아웃을 변경하지 않음)와 일치합니다.
margin을 파싱하다(root 또는 scroll) 입력 문자열 marginString에서 4개 픽셀 길이 또는 백분율의 리스트, 또는 실패를 반환합니다:
-
구성 값 리스트를 파싱 marginString에 대해 실행하고, 결과를 tokens로 저장합니다.
-
tokens에서 모든 공백 토큰을 제거합니다.
-
tokens의 길이가 4를 초과하면 실패를 반환합니다.
-
tokens에 요소가 하나도 없으면 tokens를 ["0px"]로 설정합니다.
-
tokens의 각 token을 다음과 같이 대체합니다:
-
token이 <percentage> 토큰이면, 동일한 백분율로 대체합니다.
-
그 외의 경우, 실패를 반환합니다.
-
tokens에 요소가 하나만 있으면, 그 요소를 세 번 복제하여 tokens에 추가합니다. 두 요소가 있으면 각 요소를 한 번씩 복제하여 tokens에 추가합니다. 세 요소가 있으면 두 번째 요소를 한 번 더 복제하여 tokens에 추가합니다.
-
tokens를 반환합니다.
2.3. IntersectionObserverEntry 인터페이스
[Exposed =Window ]interface {
IntersectionObserverEntry (
constructor IntersectionObserverEntryInit );
intersectionObserverEntryInit readonly attribute DOMHighResTimeStamp time ;readonly attribute DOMRectReadOnly ?rootBounds ;readonly attribute DOMRectReadOnly boundingClientRect ;readonly attribute DOMRectReadOnly intersectionRect ;readonly attribute boolean isIntersecting ;readonly attribute double intersectionRatio ;readonly attribute Element target ; };dictionary {
IntersectionObserverEntryInit required DOMHighResTimeStamp ;
time required DOMRectInit ?;
rootBounds required DOMRectInit ;
boundingClientRect required DOMRectInit ;
intersectionRect required boolean ;
isIntersecting required double ;
intersectionRatio required Element ; };
target
boundingClientRect
, 타입 DOMRectReadOnly, 읽기 전용-
DOMRectReadOnly
는target
에 대해 bounding box를 가져오기로 얻어집니다. intersectionRect
, 타입 DOMRectReadOnly, 읽기 전용-
boundingClientRect
에 대해target
의 모든 조상 clip rect(단,root
는 제외)로 교차시킨 다음, root 교차 사각형과 교차시킨 값입니다. 이 값은target
이 root 교차 사각형 내에서 실제로 보이는 부분을 나타냅니다. isIntersecting
, 타입 boolean, 읽기 전용-
target
이root
와 교차하면 true, 아니면 false입니다. 이 플래그는IntersectionObserverEntry
가 교차 상태에서 비교차 상태로 전환됨을 신호하거나,IntersectionObserverEntry
가 비교차 상태에서 교차 상태로 전환되지만 intersection rect의 영역이 0인 경우(가장자리에 맞닿거나boundingClientRect
의 영역이 0인 경우 등) 구별할 수 있게 해줍니다. intersectionRatio
, 타입 double, 읽기 전용-
boundingClientRect
에 영역이 0이 아니면,intersectionRect
영역을boundingClientRect
영역으로 나눈 값입니다. 영역이 0이면isIntersecting
이 true면 1, 아니면 0입니다. rootBounds
, 타입 DOMRectReadOnly, 읽기 전용, null 허용-
동일 출처 도메인 대상인 경우 root 교차 사각형입니다. 그 외에는
null
입니다. 만약 target이 다른 browsing context에 있다면, intersection root와 다른 좌표계를 사용하게 됩니다. 이때boundingClientRect
와intersectionRect
도 다른 좌표계가 됩니다. target
, 타입 Element, 읽기 전용-
intersection root와 교차가 변경된
Element
입니다. time
, 타입 DOMHighResTimeStamp, 읽기 전용-
이 속성은 IntersectionObserver 인스턴스가 알림을 생성할 때 기록된 교차 시점의 시간 원점 기준
DOMHighResTimeStamp
를 반환해야 합니다.
2.4. IntersectionObserverInit 딕셔너리
dictionary { (
IntersectionObserverInit Element or Document )?root =null ;DOMString rootMargin = "0px";DOMString scrollMargin = "0px"; (double or sequence <double >)threshold = 0; };
root
, 타입(Element or Document)
, null 허용, 기본값null
rootMargin
, 타입 DOMString, 기본값"0px"
-
CSS의 margin 속성과 비슷하며, 1~4개의 구성 요소 문자열입니다. 각 값은 절대 길이 또는 백분율입니다.
"5px" // 모든 margin이 5px "5px 10px" // 위 & 아래 = 5px, 오른쪽 & 왼쪽 = 10px "-10px 5px 8px" // 위 = -10px, 오른쪽 & 왼쪽 = 5px, 아래 = 8px "-10px -5px 5px 8px" // 위 = -10px, 오른쪽 = -5px, 아래 = 5px, 왼쪽 = 8px scrollMargin
, 타입 DOMString, 기본값"0px"
-
rootMargin
과 비슷하며, 1~4개의 구성 요소 문자열입니다. 각 값은 절대 길이 또는 백분율입니다.예시는 위의
rootMargin
을 참고하세요. threshold
, 타입(double or sequence<double>)
, 기본값0
-
콜백을 트리거할 임계값(들)의 목록입니다. intersectionRect 영역이 임계값 이상에서 이하로(또는 그 반대) 변경될 때 콜백이 호출됩니다.
임계값 값은 [0, 1.0] 범위여야 하며, target에 대한 bounding box를 가져오기로 생성된 사각형 영역의 백분율을 나타냅니다.
참고: 0.0은 "픽셀이 1개라도 있으면"과 동일하게 동작합니다.
3. 처리 모델
이 섹션은 사용자 에이전트가 Intersection Observer API를 구현할 때 따라야 하는 단계들을 설명합니다.
3.1. 내부 슬롯 정의
3.1.1. 문서
각 document
는 IntersectionObserverTaskQueued 플래그를 가지며, 초기값은
false입니다.
3.1.2. 요소
Element
객체는 내부 [[RegisteredIntersectionObservers]]
슬롯을 가지며, 초기값은 빈 리스트입니다.
이 리스트는 IntersectionObserverRegistration
레코드를 포함합니다.
이 레코드는 observer
속성에 IntersectionObserver
를
저장하고,
previousThresholdIndex
속성에 옵저버의 thresholds
속성 길이(-1~포함)의 숫자를 저장하며,
previousIsIntersecting
속성에 boolean 값을 저장합니다.
3.1.3. IntersectionObserver
IntersectionObserver
객체는 내부 [[QueuedEntries]]
와 [[ObservationTargets]]
슬롯을 가지며,
둘 다 빈 리스트로 초기화됩니다.
그리고 [[callback]]
슬롯이 있고,
IntersectionObserver(callback, options)
에서
초기화됩니다.
또한 내부 [[rootMargin]]
및 [[scrollMargin]]
슬롯이 있으며,
네 개의 픽셀 길이 또는 백분율의 리스트입니다.
3.2. 알고리즘
3.2.1. 새 IntersectionObserver 초기화
새
IntersectionObserver를 초기화하려면, IntersectionObserverCallback
callback과 IntersectionObserverInit
딕셔너리 options가 주어졌을 때, 다음 단계를 실행합니다:
-
this를 새로운
IntersectionObserver
객체로 설정합니다. -
this의 내부
[[callback]]
슬롯을 callback으로 설정합니다. -
options.
rootMargin
에서 margin을 파싱하려고 시도합니다. 리스트가 반환되면, this의 내부[[rootMargin]]
슬롯에 저장합니다. 그렇지 않으면, SyntaxError 예외를throw
합니다. -
options.
scrollMargin
에서 margin을 파싱하려고 시도합니다. 리스트가 반환되면, this의 내부[[scrollMargin]]
슬롯에 저장합니다. 그렇지 않으면, SyntaxError 예외를throw
합니다. -
thresholds를 options.
threshold
와 동일한 리스트로 설정합니다. -
thresholds에 0.0보다 작거나 1.0보다 큰 값이 있으면, RangeError 예외를
throw
합니다. -
thresholds를 오름차순으로 정렬합니다.
-
thresholds가 비어 있으면,
0
을 thresholds에 추가합니다. -
thresholds
속성 getter는 이 정렬된 thresholds 리스트를 반환합니다. -
this를 반환합니다.
3.2.2. 대상 요소 관찰
대상 요소 관찰하려면,
IntersectionObserver
observer와 Element
target이 주어졌을 때, 다음 단계를 따릅니다:
-
target이 observer의 내부
[[ObservationTargets]]
슬롯에 있으면, return합니다. -
intersectionObserverRegistration을
IntersectionObserverRegistration
레코드로 생성하고,observer
속성을 observer로,previousThresholdIndex
속성을-1
로,previousIsIntersecting
속성을false
로 설정합니다. -
intersectionObserverRegistration을 target의 내부
[[RegisteredIntersectionObservers]]
슬롯에 추가합니다. -
target을 observer의 내부
[[ObservationTargets]]
슬롯에 추가합니다.
3.2.3. 대상 요소 관찰 중지
대상 요소 관찰
중지하려면, IntersectionObserver
observer와 Element
target이 주어졌을 때, 다음 단계를 따릅니다:
-
IntersectionObserverRegistration
레코드 중observer
속성이 this와 같은 것을 target의 내부[[RegisteredIntersectionObservers]]
슬롯에서 제거합니다(있으면). -
target을 this의 내부
[[ObservationTargets]]
슬롯에서 제거합니다(있으면).
3.2.4. Intersection Observer 작업 큐에 추가
IntersectionObserver 작업 소스는 작업 소스이며, § 3.2.5 IntersectionObserver 알림 작업 스케줄에 사용됩니다.
Intersection Observer 작업을 큐에 추가하려면 document
document에 대해,
다음 단계를 실행합니다:
-
document의 IntersectionObserverTaskQueued 플래그가 true면 return합니다.
-
document의 IntersectionObserverTaskQueued 플래그를 true로 설정합니다.
-
작업 큐 추가를 IntersectionObserver 작업 소스에 대해
document
의 이벤트 루프에서 IntersectionObserver 알림을 실행하도록 큐에 추가합니다.
3.2.5. IntersectionObserver 알림
IntersectionObserver 알림을 document
document에 대해 실행하려면,
다음 단계를 따릅니다:
-
document의 IntersectionObserverTaskQueued 플래그를 false로 설정합니다.
-
notify list를 document의 DOM 트리에
IntersectionObserver
의root
가 포함된 모든 객체의 리스트로 설정합니다. -
notify list의 각
IntersectionObserver
객체 observer에 대해, 다음 단계를 실행합니다:-
observer의 내부
[[QueuedEntries]]
슬롯이 비어 있으면, 계속 진행합니다. -
queue를 observer의 내부
[[QueuedEntries]]
슬롯의 복사본으로 설정합니다. -
observer의 내부
[[QueuedEntries]]
슬롯을 비웁니다. -
callback을 observer의 내부
[[callback]]
슬롯의 값으로 설정합니다. -
callback을 queue를 첫 번째 인자로, observer를 두 번째 인자로, observer를 콜백 this 값으로 호출합니다. 예외가 발생하면, 예외를 보고합니다.
-
3.2.6. IntersectionObserverEntry 큐에 추가
IntersectionObserverEntry를 큐에 추가하려면 IntersectionObserver
observer, document
document, DOMHighResTimeStamp
time, DOMRect
들
rootBounds, boundingClientRect, intersectionRect, isIntersecting
플래그,
Element
target이 주어졌을 때,
다음 단계를 실행합니다:
-
IntersectionObserverEntry
를 생성하고, time, rootBounds, boundingClientRect, intersectionRect, isIntersecting, target을 전달합니다. -
이를 observer의 내부
[[QueuedEntries]]
슬롯에 추가합니다. -
Intersection Observer 작업을 큐에 추가를 document에 대해 실행합니다.
3.2.7. 대상 요소와 루트의 교차 영역 계산
target 요소와 루트의 교차 영역 계산을 하려면 target target과 intersection root root가 주어졌을 때, 다음 단계를 실행합니다:
-
intersectionRect를 target에 대해 bounding box를 가져오기의 결과로 설정합니다.
-
container를 target의 포함 블록으로 설정합니다.
-
container가 root가 아닐 때 반복합니다:
-
container가 중첩 브라우징 컨텍스트의
document
인 경우, intersectionRect를 그document
의 뷰포트로 클리핑하고, container를 브라우징 컨텍스트 컨테이너로 변경합니다. -
intersectionRect를 container의 좌표 공간으로 매핑합니다.
-
container가 스크롤 컨테이너인 경우,
IntersectionObserver
의[[scrollMargin]]
을 container의 클립 rect에 스크롤포트에 scroll margin을 적용처럼 적용합니다. -
container에 content clip 또는 css clip-path 속성이 있으면, container의 클립을 intersectionRect에 적용하여 업데이트합니다.
-
container가 브라우징 컨텍스트의 루트 요소인 경우, container를 브라우징 컨텍스트의
document
로, 그렇지 않으면 container를 포함 블록으로 변경합니다.
-
-
intersectionRect를 root의 좌표 공간으로 매핑합니다.
-
intersectionRect를 root 교차 사각형과 교차시켜 업데이트합니다.
-
intersectionRect를 반환합니다.
3.2.8. 교차 관찰 업데이트 단계 실행
교차 관찰 업데이트 단계를 실행하다는 Document document에서 타임스탬프 time이 주어졌을 때 다음 단계를 수행합니다:
-
observer list를 document의 DOM 트리에
IntersectionObserver
의root
가 포함된 모든 객체의 리스트로 설정합니다. 최상위 브라우징 컨텍스트의 경우, 암시적 루트 옵저버도 포함합니다. -
observer list의 각 observer에 대해:
-
rootBounds를 observer의 루트 교차 사각형으로 설정합니다.
-
observer의 내부
[[ObservationTargets]]
슬롯에 있는 각 target에 대해,observe()
호출 순서대로 처리합니다:-
다음과 같이 설정합니다:
-
thresholdIndex를 0으로.
-
isIntersecting를 false로.
-
targetRect를 x, y, width, height가 0인
DOMRectReadOnly
로. -
intersectionRect를 x, y, width, height가 0인
DOMRectReadOnly
로.
-
-
만약 교차점 루트가 암시적 루트가 아니고, target이 document가 교차점 루트와 같지 않은 경우, 11단계로 건너뛴다.
-
intersection root가
Element
이며, target이 intersection root의 포함 블록 체인의 자손이 아니면 11단계로 건너뜁니다. -
targetRect를 target에 대해 bounding box를 가져오기의 결과로 설정합니다.
-
intersectionRect를 교차 영역 계산 알고리즘으로 target과 observer의 intersection root에 대해 실행한 결과로 설정합니다.
-
targetArea를 targetRect의 영역으로 설정합니다.
-
intersectionArea를 intersectionRect의 영역으로 설정합니다.
-
isIntersecting를 targetRect와 rootBounds가 교차하거나 가장자리에 인접해 있으면 true로 설정합니다. 교차 영역이 0이어도(rootBounds 또는 targetRect의 영역이 0인 경우) true입니다.
-
targetArea가 0이 아니면 intersectionRatio를 intersectionArea / targetArea로. 아니면 isIntersecting이 true면
1
, false면0
으로 설정합니다. -
thresholdIndex를 observer.
thresholds
중 intersectionRatio보다 큰 첫 번째 항목의 인덱스로, intersectionRatio가 마지막 값 이상이면 observer.thresholds
의 길이로 설정합니다. -
intersectionObserverRegistration을 target의 내부
[[RegisteredIntersectionObservers]]
슬롯에서observer
속성이 observer인 레코드로 설정합니다. -
previousThresholdIndex를 intersectionObserverRegistration의
previousThresholdIndex
값으로 설정합니다. -
previousIsIntersecting를 intersectionObserverRegistration의
previousIsIntersecting
값으로 설정합니다. -
thresholdIndex가 previousThresholdIndex와 다르거나, isIntersecting이 previousIsIntersecting과 다르면, IntersectionObserverEntry 큐에 추가를 실행합니다. observer, time, rootBounds, targetRect, intersectionRect, isIntersecting, target을 전달합니다.
-
thresholdIndex를 intersectionObserverRegistration의
previousThresholdIndex
에 할당합니다. -
isIntersecting을 intersectionObserverRegistration의
previousIsIntersecting
에 할당합니다.
-
-
3.3. IntersectionObserver 생명주기
IntersectionObserver
객체는 다음 두 조건이 모두 충족될 때까지 생존합니다:
- 옵저버에 대한 스크립트 참조가 더 이상 없음
- 옵저버가 어떤 대상도 관찰하지 않음
IntersectionObserver
객체는 unobserve()
메서드가 대상 인자로 호출되거나, disconnect()
메서드가 호출될 때까지 계속 관찰합니다.
3.4. 외부 명세 통합
3.4.1. HTML 처리 모델: 이벤트 루프
Intersection Observer 처리 단계는 HTML 이벤트 루프 처리 모델의 "렌더링 업데이트" 단계의 하위 단계로 존재합니다.
3.4.2. 초기 IntersectionObserver 대상 대기
document
객체는 다음 조건을 모두 만족하는 IntersectionObserver
가 하나 이상 있을 때 초기 IntersectionObserver 대상 대기가 있다고 합니다:
- observer의
root
가 document에 포함됨(최상위 브라우징 컨텍스트의 경우 암시적 루트 옵저버도 포함됨) - observer가
[[ObservationTargets]]
슬롯에IntersectionObserverEntry
가 아직 큐에 추가되지 않은 target을 하나 이상 가지고 있음
HTML 이벤트 루프 처리 모델의 "렌더링 업데이트" 단계에서, "불필요한 렌더링" 단계는 다음 조건이 추가되어 렌더링 업데이트를 건너뛸 수 있습니다:
- document에 초기 IntersectionObserver 대상 대기가 없음
4. 접근성 고려사항
이 섹션은 비규범적입니다.
IntersectionObserver 명세(본 문서)의 핵심에는 알려진 접근성 고려사항이 없습니다. 그러나 이 명세를 활용하거나 참조하는 관련 명세 및 제안들이 있으며, 이들에는 자체적인 접근성 고려사항이 있을 수 있습니다. 특히, HTML § 2.5.7 지연 로딩 속성과 CSS Containment 2 § 4 요소의 콘텐츠를 완전히 숨기기: content-visibility 속성 명세는 HTML § 6.9 페이지 내 찾기, HTML § 6.6.3 tabindex 속성, 공간 네비게이션 등에 영향을 줄 수 있습니다.
5. 프라이버시 및 보안
이 섹션은 비규범적입니다.
이 API와 관련된 주요 프라이버시 문제는 교차 출처 iframe(즉, 교차-출처-도메인 대상 케이스)에서 실행되는 코드에 정보를 제공할 수 있다는 점입니다. 특히:
-
iframe이 글로벌 뷰포트 내에 있는지 여부를 공개하는 것이 프라이버시에 미치는 영향에 대해 보편적인 합의가 없습니다.
-
API가 글로벌 뷰포트의 기하에 대한 정보를 탐색하는 데 사용될 위험이 있으며, 이를 통해 사용자의 하드웨어 구성까지 추론할 수 있습니다.
rootMargin
및scrollMargin
의 효과를 비활성화하고, 교차 출처 도메인 대상에 대해rootBounds
를 숨기는 이유는 이러한 탐색을 방지하기 위한 것입니다.
IntersectionObserver
등장 이전에도
웹 개발자들은 IntersectionObserver
로
얻을 수 있는 정보를
다른 API를 기발하고(때로는 기괴하게) 활용해 추출했습니다.
실질적으로, 이 API는 이미 다른 방식으로 얻을 수 있던 정보 이상을 공개하지 않습니다.
또 다른 고려 사항은 IntersectionObserver
가 DOMHighResTimeStamp
를
사용한다는 점입니다.
이 값에도 자체적인 프라이버시 및 보안 고려사항이 있지만,
IntersectionObserver
가
타이밍 관련 익스플로잇에 취약할 가능성은 낮습니다.
타임스탬프는 렌더링 업데이트마다 최대 한 번만 생성되며(§ 3.4.1 HTML 처리 모델: 이벤트 루프 참조),
이는 일반적인 타이밍 공격에는 너무 드뭅니다.
6. 국제화
이 섹션은 비규범적입니다.
국제화 관련 알려진 문제는 없습니다.
7. 감사의 글
이 명세를 개선하는 데 기술적 의견과 제안을 제공한 모든 기여자에게 특별히 감사드립니다.