Intersection Observer API
Baseline
Widely available
*
This feature is well established and works across many devices and browser versions. Itâs been available across browsers since 2019ë 3ì.
* Some parts of this feature may have varying levels of support.
Intersection Observer APIë ìì ìì ëë ìµìì 문ìì viewportì ëì ìì ì¬ì´ì ë³í를 ë¹ë기ì ì¼ë¡ ê´ì°°í ì ìë ìë¨ì ì ê³µí©ëë¤.
ìì¬ì ì¼ë¡, ììì ê°ìì± ëë ê´ë ¨ë ë ìì ì¬ì´ì ìëì ê°ìì±ì ê°ì§íë ê²ì í´ê²°ì± ì ì 뢰í ì ìê³ ë¸ë¼ì°ì ì ì¬ì©ìê° ì ê·¼íë ì¬ì´í¸ë¥¼ ëë¦¬ê² ë§ëë ì´ë ¤ì´ ìì ì´ììµëë¤. Webì´ ì±ìí´ì§ì ë°ë¼, ì´ë¬í ì¢ ë¥ì ì ë³´ì ìêµ¬ê° ëì´ë¬ìµëë¤. êµì°¨ ì ë³´ë ë¤ìê³¼ ê°ì ë§ì ì´ì ë¡ íìí©ëë¤.
- íì´ì§ê° ì¤í¬ë¡¤ ë ë ì´ë¯¸ì§ì ëë ë¤ë¥¸ 컨í ì¸ ì ì§ì° ë¡ë©(Lazy-loading) ë©ëë¤.
- ì¤í¬ë¡¤í ë ë ë§ì 컨í ì¸ ê° ë¡ëëê³ ë ëë§ ëë "무í ì¤í¬ë¡¤" ì¹ ì¬ì´í¸ë¥¼ 구íí¨ì¼ë¡ì¨, ì¬ì©ìê° íì´ì§ë¥¼ ë길 íìê° ììµëë¤.
- ê´ê³ ììµ ì°ì ì ìí´ ê´ê³ ê°ìì±ì ë³´ê³ í©ëë¤.
- ì¬ì©ìê° ê²°ê³¼ë¥¼ ë³¼ ì ììì§ ì¬ë¶ì ë°ë¼ ìì ëë ì ëë©ì´ì íë¡ì¸ì¤ë¥¼ ìíí ì§ ì¬ë¶ë¥¼ ê²°ì í©ëë¤.
과거ì êµì°¨ ê°ì§ 구íì ìí¥ì ë°ë 모ë ììì ëí´ íìí ì 보를 ì¶ì í기 ìí´ ì´ë²¤í¸ ì²ë¦¬ê¸°ì Element.getBoundingClientRect()ì ê°ì ë©ìë를 í¸ì¶íë 루í를 í¬í¨íììµëë¤. 모ë ì½ëê° ë©ì¸ ì¤ë ëìì ì¤íë기 ë문ì, ì´ ì¤ íëë¼ë ì±ë¥ 문ì 를 ì¼ì¼í¬ ì ììµëë¤. ì´ë¬í í
ì¤í¸ì í¨ê» ì¬ì´í¸ê° ë¡ë ë ë, ìì í 못ìê²¨ì§ ì ìììµëë¤.
무í ì¤í¬ë¡¤ì ì¬ì©íë ì¹ íì´ì§ë¥¼ ìê°í´ë´ ìë¤. 주기ì ì¼ë¡ íì´ì§ì ë°°ì¹ëë ê´ê³ 를 ê´ë¦¬í기 ìí´ ê³µê¸ì ì²´ê° ì ê³µíë ë¼ì´ë¸ë¬ë¦¬ë¥¼ ì¬ì©íê³ , ì¬ê¸°ì 기ì ì ëë©ì´ì ê·¸ëí½ì´ ìì¼ë©°, ê³µì§ ë°ì¤ ê°ì ê²ë¤ì 그리ë ì¬ì©ì ì ì ë¼ì´ë¸ë¬ë¦¬ë ì¬ì©í©ëë¤. ì´ ê°ê°ìë í´ë¹ êµì°¨ ê°ì§ 루í´ì´ ìê³ ëª¨ë ë©ì¸ ì¤ë ëìì ì¤íë©ëë¤. ì¹ ì¬ì´í¸ ì ììë ê·¸ë¤ì´ ì¬ì©íë ë ê°ì§ ë¼ì´ë¸ë¬ë¦¬ì ë¤ì´ìë ë´ë¶ ìì ì ëí´ì ì¡°ê¸ë§ ì기 ë문ì ì´ë¬í ì¼ì´ ì¼ì´ëë ì§ë 깨ë«ì§ 못í ê²ì ëë¤. ì ì ê° íì´ì§ë¥¼ ì¤í¬ë¡¤ í ë, ì´ë¬í êµì°¨ ê°ì§ 루í´ì ì¤í¬ë¡¤ ì²ë¦¬ ì½ëê° ì¤íëë ëì ì§ìì ì¼ë¡ ë°ìíì¬ ì¬ì©ìê° ë¸ë¼ì°ì , ì¹ì¬ì´í¸, ì»´í¨í°ì ë¶ë§ì ëë¼ê² í©ëë¤.
Intersection Observer APIë í¹ì ììê° ë¤ë¥¸ ìì(ëë viewport)ìì êµì°¨ì ì ë¤ì´ê°ê±°ë ëê° ë ëë ë ìì ê°ì êµì°¨ì ì´ ì§ì ë ìë§í¼ ë³íë ë ì¤íëë ì½ë°± í¨ì를 ì½ëì ë±ë¡í ì ììµëë¤. ì´ ë°©ë²ì¼ë¡, ì¬ì´í¸ë ëì´ì ì´ë¬í ì¢ ë¥ì ìì êµì°¨ë¥¼ ê°ìí기 ìí´ ë©ì¸ ì¤ë ëì ì무ê²ë í íìê° ìê³ , ë¸ë¼ì°ì ë ì í©íë¤ê³ íë¨ëë ëë¡ êµì°¨ ê´ë¦¬ë¥¼ ìì ë¡ê² ìµì íí ì ììµëë¤.
Intersection Observer APIê° ìë ¤ì£¼ì§ ìë í ê°ì§: ê²¹ì¹ë í½ì ì ì íí ìë 구체ì ì¼ë¡ ì´ë¤ í½ì ì¸ì§ë¥¼ ìë ¤ì£¼ì§ ëª»í©ëë¤. ê·¸ë¬ë ì´ APIë "ì½ N% ì ë ê²¹ì¹ë¤ë©´ ì´ë¤ ìì ì ìíí´ì¼ íë¤"ë ë ì¼ë°ì ì¸ ì¬ì© ì¬ë¡ë¥¼ ë¤ë£¹ëë¤.
êµì°¨ ê´ì°°ì ê°ë ê³¼ ì¬ì©
Intersection Observer APIë ë¤ìê³¼ ê°ì ìí©ì´ ë°ìíì ë í¸ì¶ëë ì½ë°± í¨ì를 구ì±í ì ììµëë¤.
- ëì ììë 기기ì ë·°í¬í¸ ëë í¹ì ììì êµì°¨í©ëë¤. í¹ì ììë Intersection Observer APIì 목ì ì ë°ë¼ ë£¨í¸ ìì ëë 루í¸ë¼ê³ ë¶ë¦½ëë¤.
- observerê° ìµì´ë¡ ëì ìì를 ê´ì°°íë¼ê³ ìì² ë°ì ìì ì ëë¤.
ì¼ë°ì ì¼ë¡, ëì ììì ê°ì¥ ê°ê¹ì´ ì¤í¬ë¡¤ ê°ë¥í ìì ììë íê²ììê° ì¤í¬ë¡¤ ê°ë¥í ììì íì ììê° ìë ê²½ì°, ì¥ì¹ ë·°í¬í¸ì ê´ë ¨ë êµì°¨ ë³í를 ê´ì°°íê³ ì¶ì´í©ëë¤. ì¥ì¹ ë·°í¬í¸ì ê´ë ¨ë êµì°¨ë¥¼ ê´ì°°í기 ìí´ìë root ìµì
ì nullì ì§ì í´ì¼ í©ëë¤. êµì°¨ ê´ì°°ì ìµì
ì ëí ë ìì¸í ì¤ëª
ì ìí´ì ê³ì ì½ì´ì¼ í©ëë¤.
ë·°í¬í¸ë¥¼ 루í¸ë¡ ì¬ì©íëì§ ë¤ë¥¸ ììë¤ì 루í¸ë¡ ì¬ì©íëì§, APIë ê°ì ë°©ìì¼ë¡ ëìíì¬ ëì ììì ê°ìì±ì´ ë³ííì¬ ìì²í ìë§í¼ 루í¸ì êµì°¨í ëë§ë¤ ì¬ì©ìê° ì ê³µí ì½ë°±í¨ì를 ì¤íí©ëë¤.
íê² ììì íê² ììì ë£¨í¸ ì¬ì´ì êµì°¨ì ì ëë intersection ratio ì ëë¤. 0.0ê³¼ 1.0 ì¬ì´ì ê°ì¼ë¡ ë³´ì´ë ëì ììì ë°±ë¶ì¨ì ëíë ëë¤.
êµì°¨ ê´ì°°ì ìì±í기
intersection observerë ìì±ì를 í¸ì¶íê³ , thresholdê° í ë°©í¥ í¹ì ë¤ë¥¸ ë°©í¥ì¼ë¡ êµì°¨í ëë§ë¤ ì¤íí기 ìí callback í¨ì를 ì ë¬íì¬ ìì±í©ëë¤.
let options = {
root: document.querySelector("#scrollArea"),
rootMargin: "0px",
threshold: 1.0,
};
let observer = new IntersectionObserver(callback, options);
thresholdê° 1.0ì´ë¼ë ì미ë root ìµì
ì¼ë¡ ì§ì ë ìì ë´ìì íê² ììê° 100% ë³´ì´ë©´ ì½ë°±ì´ í¸ì¶ëë¤ë ì미ì
ëë¤. ë¤ìê³¼ ê°ì íëê° ììµëë¤.
êµì°¨ ê´ì°°ì ìµì
IntersectionObserver() ìì±ìì ì ë¬ëë options ê°ì²´ë observerì ì½ë°±ì´ ì¸ì í¸ì¶ëëì§ë¥¼ ì ì´í ì ìê² í´ì¤ëë¤. ì´ ê°ì²´ë ë¤ìê³¼ ê°ì íë를 ê°ì§ê³ ììµëë¤.
root-
ëì ê°ìì±ì ì²´í¬í기 ìí ë·°í¬í¸ë¡ ì¬ì©ëë ìì. ë°ëì íê²ì ìì ììì´ì´ì¼ í©ëë¤. ë§ì½ ë·°í¬í¸ë¥¼ ì§ì íì§ ìê±°ë
nullì´ë©´ ë¸ë¼ì°ì ë·°í¬í¸ê° 기본ì¼ë¡ ì¤ì ë©ëë¤. rootMargin-
ë£¨í¸ ì£¼ìì ì¬ë°±ì ëë¤. CSS
marginìì±ê³¼ ë¹ì·í ê°ì ê°ì§ ì ììµëë¤. ìì."10px 20px 30px 40px"(ì, ì¤ë¥¸ìª½, ìë, ì¼ìª½). ê°ì ë°±ë¶ì¨ì´ ë ì ììµëë¤. ì´ ê°ì ì§í©ì êµì°¨ ì§ì ì ê³ì°í기 ì ì ë£¨í¸ ìì ê²½ê³ ë°ì¤ì ê° ì¬ì´ë ê°ì ë리거ë ì¤ì¼ ì ììµëë¤. 기본 ê°ì 0ì ëë¤. threshold-
ê´ì°°ìì ì½ë°±ì´ 무조건 ì¤íëì´ì¼ íë ëìì ê°ìì± ë°±ë¶ì¨ì ëíë´ë ì«ì ëë ì«ì ë°°ì´ì ëë¤. ë§ì½ ê°ìì±ì´ 50% ì§ì ì ëë ê²½ì°ë§ ê°ì§íê³ ì¶ë¤ë©´, 0.5를 ì§ì íì¬ ì¬ì©í ì ììµëë¤. ë§ì½ ê°ìì±ì´ 25%ë§í¼ ëì´ê° ëë§ë¤ ì½ë°±ì ì¤ííê³ ì¶ë¤ë©´, [0, 0.25, 0.5, 0.75, 1]ì ì§ì íì¬ ì¬ì©í ì ììµëë¤. 기본 ê°ì 0 ì ëë¤. (1 í½ì ì´ë¼ë ë³´ì´ë©´, ì½ë°±ì´ ì¤íë©ëë¤.) 1.0ì ê°ì 모ë í½ì ì´ ê°ì ìíê° ë ëê¹ì§ ìê³ê°ì´ íµê³¼ëì§ ìëë¤ë ê²ì ì미í©ëë¤.
ê´ì°°í ìì를 ëìì¼ë¡ í기
ê´ì°°ì를 ìì±íë¤ë©´, ê´ì°°í íê² ìì를 ì ë¬í´ì¼ í©ëë¤.
let target = document.querySelector("#listItem");
observer.observe(target);
// observer를 ìí´ ì¤ì í ì½ë°±ì ë°ë¡ ì§ê¸ ìµì´ë¡ ì¤íë©ëë¤
// ëìì ê´ì°°ìì í ë¹í ëê¹ì§ 기ë¤ë¦½ëë¤. (íê²ì´ íì¬ ë³´ì´ì§ ìëë¼ë)
ì¸ì ë ì§ íê² ììê° IntersectionObserverì ì§ì ë ìê³ê°ì ë§ì¡±ìí¤ë©´, ì½ë°±ì í¸ì¶ë©ëë¤. ì½ë°±ì IntersectionObserverEntry ê°ì²´ì ê´ì°°ì 목ë¡ì ë°ìµëë¤.
let callback = (entries, observer) => {
entries.forEach((entry) => {
// ê° ìí¸ë¦¬ë ê´ì°°ë íëì êµì°¨ ë³íì ì¤ëª
í©ëë¤.
// ëì ìì:
// entry.boundingClientRect
// entry.intersectionRatio
// entry.intersectionRect
// entry.isIntersecting
// entry.rootBounds
// entry.target
// entry.time
});
};
ì½ë°±ì´ ìì í ìí¸ë¦¬ 목ë¡ì êµì°¨ ìíì ë³í를 ë³´ê³ í ê° ëìì ëí íëì ìí¸ë¦¬ë¥¼ í¬í¨í©ëë¤. ìí¸ë¦¬ê° íì¬ ë£¨í¸ì êµì°¨íë ìì를 ëíë´ëì§ ë³´ê¸° ìí´ isIntersecting ìì± ê°ì íì¸í©ëë¤.
ì½ë°±ì´ ë©ì¸ì¤ë ëìì ì¤íëë ê²ì ì ìí´ì¼ í©ëë¤. ê°ë¥í í ìµëí 빨리 ëìí´ì¼ í©ëë¤. ë§ì½ ìê° ìë¹ê° íìí ì¼ì´ ë§ë¬´ë¦¬ ëì´ì¼ íë¤ë©´, Window.requestIdleCallback()ì ì¬ì©íì¸ì.
ëí, root ìµì
ì ì§ì íë¤ë©´, ëìì ë°ëì ë£¨í¸ ììì íì ììì´ì´ì¼ë§ íë¤ë ì ì ëª
ì¬í´ì¼ í©ëë¤.
êµì°¨ ê³ì° ë°©ë²
Intersection Observer APIê° ê³ ë ¤íë 모ë ììì ì§ì¬ê°íì ëë¤. ë¶ê·ì¹í 모ìì ììë 모ë ìì를 ëë¬ì¸ë ë¶ë¶ë¤ì ê°ì¥ ìì ì§ì¬ê°íì´ ì°¨ì§íë ê²ì¼ë¡ ì¬ê²¨ì§ëë¤. ë¹ì·íê², ììì ë³´ì´ë ë¶ë¶ì´ ì§ì¬ê°íì´ ìëë©´, ììì êµì°¨íë ì§ì¬ê°íì´ ììì ë³´ì´ë 모ë ë¶ë¶ì í¬í¨íë ê°ì¥ ìì ì§ì¬ê°íì¼ë¡ ê°ì£¼ë©ëë¤.
IntersectionObserverEntryìì ì ê³µíë ë¤ìí ìì±ì´ êµì°¨ë¥¼ ì´ë»ê² ì¤ëª
íëì§ë¥¼ ì¡°ê¸ ì´í´íë ê²ì´ ì ì©í©ëë¤.
êµì°¨ 루í¸ì ë£¨í¸ ì¬ë°±
컨í
ì´ëì ììì êµì°¨ë¥¼ ë°ë¼ê°ê¸° ì ì, ì°ë¦¬ë 컨í
ì´ëê° ë¬´ìì¸ì§ë¥¼ ììì¼ í©ëë¤. 컨í
ì´ëë êµì°¨ ë£¨í¸ ëë ë£¨í¸ ìì ì
ëë¤. ê´ì°° ëì ììì ìì ììì¸ documentì í¹ì ììì´ê±°ë 컨í
ì´ëë¡ ë¬¸ì ë·°í¬í¸ë¥¼ ì¬ì©í기 ìí nullì´ ë ì ììµëë¤.
ë£¨í¸ êµì°¨ ì§ì¬ê°íì ëì ìì를 íì¸í기 ìí ì§ì¬ê°íì ëë¤. ì´ ì§ì¬ê°íì ë¤ìê³¼ ê°ì´ ê²°ì ë©ëë¤.
- ë§ì½ êµì°¨ 루í¸ê° ì ëì ì¸ ë£¨í¸ë¼ë©´(ì¦, ìµìë¨
Document), ë£¨í¸ êµì°¨ ì§ì¬ê°íì ë·°í¬í¸ ì§ì¬ê°íì ëë¤. - êµì°¨ 루í¸ì overflow clipì´ ìë ê²½ì°, ë£¨í¸ êµì°¨ ì§ì¬ê°íì ë£¨í¸ ììì 컨í ì¸ ììì ëë¤.
- ì ë ê°ì§ ê²½ì°ê° ìëë¼ë©´, root êµì°¨ ì§ì¬ê°íì êµì°¨ ë£¨í¸ ê²½ê³ í´ë¼ì´ì¸í¸ ì§ì¬ê°íì
ëë¤.(
getBoundingClientRect()를 í¸ì¶íì¬ ë°íë)
ë£¨í¸ êµì°¨ ì§ì¬ê°íì IntersectionObserver를 ìì±í ë, root margin , rootMarginì ì¤ì í¨ì¼ë¡ ì¸í´ ì¡°ì ë ì ììµëë¤. rootMargin ê°ì ìµì¢
êµì°¨ ë£¨í¸ ê²½ê³ (ì½ë°±ì´ ì¤íë ë IntersectionObserverEntry.rootBoundsì ê³µê°ë)를 ìì±í기 ìí´ êµì°¨ ë£¨í¸ ê²½ê³ ë°ì¤ì ê° ì¸¡ë©´ì ëí´ ì¤íì
ì ì ìí©ëë¤.
Thresholds
ë§¤ë² ëì ììê° ì¼ë§ë ë³´ì´ëì§ì 극미í ë³íë§ë¤ ë³´ê³ íë ê²ë³´ë¤ Intersection Observer APIë thresholds 를 ì¬ì©í©ëë¤. ê´ì°°ì를 ìì±í ë, íë ëë íë ì´ìì ë³´ì´ë ëì ììì ë°±ë¶ì¨ì ëíë´ë ì«ì ê°ì ì ê³µí ì ììµëë¤. ê·¸ë° ë¤ì, APIë ì´ë¬í ìê³ê°ì ëì´ê°ë ê°ìì± ë³ê²½ ì¬íë§ ë³´ê³ í©ëë¤.
ì를 ë¤ì´, ëìì ê°ìì±ì´ ê° 25% ì§ì ë³´ë¤ í¬ê±°ë ìì ëë§ë¤ ë³´ê³ ë¥¼ ë°ê³ ì¶ë¤ë©´, ê´ì°°ì를 ìì±í ë [0, 0.25, 0.5, 0.75, 1]ë¡ ì´ë£¨ì´ì§ ìê³ê° 목ë¡ì ì§ì í´ì¼ í©ëë¤.
ì½ë°±ì´ í¸ì¶ë ë, ì´ë ë°©í¥ììë ë
¸ì¶ë ìì´ ìê³ê° ì¤ íë를 ì´ê³¼íë ë£¨í¸ ë³í를 êµì°¨íë ì ëê° ê´ì°°ë ê° ëìì ëí IntersectionObserverEntry ê°ì²´ 목ë¡ì ë°ìµëë¤.
ìí¸ë¦¬ì isIntersecting ìì±ì ê´ì°°í¨ì¼ë¡ì¨ ëìì´ íì¬ ë£¨í¸ë¥¼ êµì°¨íë ê²ì ë³¼ ì ììµëë¤. ë§ì½ í´ë¹ ê°ì´ true ë¼ë©´, ëìì ìµìí ë¶ë¶ì ì¼ë¡ ë£¨í¸ ììë 문ìì êµì°¨íê³ ììµëë¤. ì´ë¥¼ íµí´ ìí¸ë¦¬ë êµì°¨íë ìììì ë ì´ì êµì°¨íì§ ìë ììë¡ì ì íì ëíë´ê±°ë êµì°¨íì§ ìììì êµì°¨íë ì íì¼ë¡ ëíë¼ ì ììµëë¤.
êµì°¨ê° ì íì´ ë ê° ì¬ì´ì ê²½ê³ ëë boundingClientRectê° 0ì¸ ììì ë°ë¥´ë ê²½ì°ì ë°ìíë 무조건 êµì°¨íë ì§ì¬ê°íì´ ì¡´ì¬í ì ìë¤ë ê²ì 주목í´ì¼ í©ëë¤. ê²½ê³ì ì ê³µì íë ëìê³¼ 루í¸ì ìíë êµì°¨ ìíë¡ì ì íì´ ì¶©ë¶íì§ ìë¤ê³ ì¬ê²¨ì§ ì ììµëë¤.
ì´ë»ê² ìê³ê°ì´ ëìíë ì§ë¥¼ ë껴보기 ìí´ì, ìë ìì를 ì¤í¬ë¡¤ í´ë´ ìë¤. ê·¸ ìì ê° ìì¹ ë ììë ë¤ ëª¨ì리ì ë³´ì´ë ììì ë°±ë¶ì¨ì ë³´ì¬ì£¼ê³ , ë°ë¼ì 컨í ì´ë를 ì¤í¬ë¡¤í ë ìê°ì´ ì§ë¨ì ë°ë¼ ì´ ë¹ì¨ì´ ë³ííë ê²ì ë³¼ ì ììµëë¤. ê° ììë ë¤ë¥¸ ìê³ê°ì ê°ì§ê³ ììµëë¤.
- 첫ë²ì§¸ ììë ê° ê°ìì± ë°±ë¶ì¨ì ëí ìê³ê°ì ê°ì§ê³ ììµëë¤. ì¦,
IntersectionObserver.thresholds목ë¡ì[0.00, 0.01, 0.02, /*â¦,*/ 0.99, 1.00]ì ëë¤. - ëë²ì§¸ ììë 50% ì§ì ì íëì ìê³ê°ì ê°ì§ê³ ììµëë¤.
- ì¸ë²ì§¸ ììë ê°ìì±ì 10% ë§ë¤ ìê³ê°ì ê°ì§ê³ ììµëë¤. (0%, 10%, 20%, ë±.).
- ë§ì§ë§ ììë ê° 25% ë§ë¤ ìê³ê°ì ê°ì§ê³ ììµëë¤.
ìë¼ë´ê¸°ì êµì°¨ ì§ì¬ê°í
ë¸ë¼ì°ì ë ë¤ìê³¼ ê°ì´ ìµì¢ êµì°¨ ì§ì¬ê°íì ê³ì°í©ëë¤. êµì°¨ê° ì¼ì´ë ë를 ë ì íí ì´í´í기 ìí´ì ìë ìì를 ì´í´íë ê²ì ëìì´ ë©ëë¤.
- ëì ììì ê²½ê³ ì§ì¬ê°í (ì¦, ìì를 구ì±íë 모ë ì»´í¬ëí¸ì ê²½ê³ ìì를 ìì í ëë¬ì¸ë ì ì¼ ìì ì§ì¬ê°í)ì íê²ì
getBoundingClientRect()ë¡ë¶í° ì»ìµëë¤. ì´ê±´ ìë§ ê°ì¥ í° êµì°¨ ì§ì¬ê°íì ëë¤. ìë ë¨ì ìììì êµì°¨ ëì§ ìë ì´ë¤ ë¶ë¶ë ì ê±°í©ëë¤. - ëìì ì§ê³ ìì ë¸ë¡ìì ììíì¬ ë°ì¼ë¡ ë»ì´ ëê°ë©´ì, í¬í¨ë ë¸ë¡ì ìë¼ë¸ ì¡°ê°ì´ ìë ê²½ì° êµì°¨ ì§ì¬ê°íì ì ì©ë©ëë¤. ë¸ë¡ì ìë¼ë¸ ì¡°ê°ì ë ê° ë¸ë¡ì êµì°¨ì
overflowìì±ì ìí´ í¹ì ë ìë¼ë´ê¸° 모ëê° ìë¤ë©´ ì´ë¥¼ 기ë°ì¼ë¡ ê²°ì ë©ëë¤.overflow를visibleì´ ìë ê²ì ì¤ì íë©´ clippingì´ ë°ìí ì ììµëë¤. - í¬í¨ë ìì ì¤ íëê° ì¤ì²©ë ë¸ë¼ì°ì§ 컨í
ì¤í¸(
<iframe>ì ë¤ì´ìë 문ìì ê°ì)ì 루í¸ë¼ë©´, êµì°¨ ì¬ê°íì í¬í¨ë 컨í ì¤í¸ì ë·°í¬í¸ì ê³ ì ëê³ , 컨í ì´ë를 ë°ë¼ 컨í ì´ëì í¬í¨ë ë¸ë¡ê³¼ ì쪽ì¼ë¡ì ë°ë³µì´ ê³ìë©ëë¤.<iframe>ì ìµìë¨ ììì ëë¬íë©´, êµì°¨ ì¬ê°íì íë ìì ë·°í¬í¸ì ê³ ì ëê³ , ê·¸ íë ìì ë¶ëª¨ ììë êµì°¨ 루í¸ë¥¼ ë°ë¼ ë°ë³µë ë¤ì ë¸ë¡ì´ ë©ëë¤. - ì쪽ì¼ë¡ì ë°ë³µì´ êµì°¨ 루í¸ì ëë¬íë©´, ê²°ê³¼ ì¬ê°íì´ êµì°¨ 루í¸ì êµì°¨ ê³µê°ì 매íë©ëë¤.
- ê²°ê³¼ ì¬ê°íì root intersection rectangleê³¼ êµì°¨íì¬ ê°±ì ë©ëë¤.
- ìµì¢
ì ì¼ë¡ ì´ ì¬ê°íì´ ëì
documentì êµì°¨ ê³µê°ì 매íë©ëë¤.
êµì°¨ ë³í ì½ë°±
ë£¨í¸ ìì ë´ì ë³´ì´ë ëì ììì ìì´ ìê³ê° ê°ìì±ì ì§ë ë, IntersectionObserver ê°ì²´ì ì½ë°±ì´ ì¤íë©ëë¤. ì½ë°±ì 모ë êµì°¨ë ê° ìê³ê° ì¤ íëì©, IntersectionObserverEntry ê°ì²´ë¤ì ë°°ì´ê³¼ IntersectionObserver ê°ì²´ ìì²´ì ëí 참조를 ì
ë ¥ì¼ë¡ ë°ìµëë¤.
목ë¡ì ìë ê° ìí¸ë¦¬ë êµì°¨ë íëì ìê³ê°ì ì미íë IntersectionObserverEntry ê°ì²´ì´ê³ , ê° ìí¸ë¦¬ê° 주ì´ì§ ììì ë£¨í¸ ììê° ì¼ë§ë êµì°¨íë ì§, ììê° êµì°¨íê³ ìëì§ì ëí ì¬ë¶, ê·¸ë¦¬ê³ ì íì´ ë°ìí ìì¹ë¥¼ ì¤ëª
í©ëë¤.
ìë ììì ëì¤ë ì½ë ì¤ëí«ì ììê° êµì°¨íì§ ìì ëë¶í° 루í¸ë¥¼ ìµì 75% ì´ì êµì°¨í ë ì¼ë§ë ì ííë ì§ë¥¼ ì¸ë ì¹´ì´í°ë¥¼ ì ì§íë ì½ë°±ì ë³´ì¬ì¤ëë¤. ìê³ê°ì´ 0.0 (기본)ì¸ ì½ë°±ì approximately isIntersecting ë¶ë¦¬ì¸ ê°ì ì íë ë í¸ì¶ë©ëë¤. ë°ë¼ì ì¤ëí«ì 먼ì ì íì´ ê¸ì ì ì¸ì§ íì¸íê³ , intersectionRatio ê° 75%를 ëì ë ì¹´ì´í°ê° ì¦ê°í©ëë¤.
const intersectionCallback = (entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
let elem = entry.target;
if (entry.intersectionRatio >= 0.75) {
intersectionCounter++;
}
}
});
};
ì¸í°íì´ì¤
IntersectionObserver-
Intersection Observer APIì 주ì ì¸í°íì´ì¤. ê°ì êµì°¨ ì¤ì ì¼ë¡ ê°ì ìê´ ìì´ ëì ìì를 ê´ì°°í ì ìë ê´ì°°ì ìì±ê³¼ ê´ë¦¬ë¥¼ ìí´ ë©ìë를 ì ê³µí©ëë¤. ê° ê´ì°°ìë íë ëë ê·¸ ì´ìì ëì ììì ê³µì ë ìì ìì ëë ìµìë¨
Documentviewport ì¬ì´ì êµì°¨ ììì ë¹ë기ì ì¼ë¡ ë³í를 ê°ì§í ì ììµëë¤. ìì ìì ëë ë·°í¬í¸ë root ë¡ ë¶ë¦½ëë¤. IntersectionObserverEntry-
ëì ììì ì ííë í¹ì ìê°ì ë£¨í¸ ì»¨í ì´ë ì¬ì´ì êµì°¨ë¥¼ ë§í©ëë¤. ì´ë¬í ì¢ ë¥ì ê°ì²´ë
IntersectionObserverì½ë°±ì ì ë ¥ ëëIntersectionObserver.takeRecords()를 í¸ì¶íë ì¤ì§ ë ê°ì§ ë°©ë²ì¼ë¡ë§ ì»ì ì ììµëë¤.
ê°ë¨í ìì
ì´ ê°ë¨í ìì ë ëì ììê° ì´ë ì ë ê°ìí ëëì§ì ë°ë¼ ììê³¼ í¬ëª ëê° ë³íí©ëë¤. Intersection Observer API를 íµí íì´ë° ìì ê°ìì±, ì¼ë ¨ì ìì(ì: ê´ê³ )ê° ì¬ì©ììê² íìëë ìê°ì 측ì íê³ , íµê³ë¥¼ 기ë¡íê±°ë ìì를 ê°±ì íì¬ ì ë³´ì ë°ìíë ë°©ë²ì ë³´ì¬ì£¼ë ë ê´ë²ìí ìì 를 ì°¾ì ì ììµëë¤.
HTML
ì´ ìì ì HTMLì ëìì´ ë (ì°½ìì ì¸ ID "box") ë°ì¤ì¸ 기본 ììì ë°ì¤ ë´ì ì¼ë¶ 컨í
ì¸ ë¡ ë§¤ì° ì§§ìµëë¤.
<div id="box">
<div class="vertical">Welcome to <strong>The Box!</strong></div>
</div>
CSS
CSSë ì´ ìì ìì ê·¸ë¤ì§ ì¤ìíì§ ììµëë¤. ìì를 ë°°ì¹íê³ background-colorì border ìì±ì´ CSS transitionsì ì°¸ì¬í ì ìëë¡ ì¤ì íì¬, ììê° ë ë§ì´ í¹ì ë ì ê² ë³´ì´ì§ ìì ë ììì ë³íì ìí¥ì 주기 ìí´ ì¬ì©ë©ëë¤.
#box {
background-color: rgba(40, 40, 190, 1);
border: 4px solid rgb(20, 20, 120);
transition:
background-color 1s,
border 1s;
width: 350px;
height: 350px;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.vertical {
color: white;
font: 32px "Arial";
}
.extra {
width: 350px;
height: 350px;
margin-top: 10px;
border: 4px solid rgb(20, 20, 120);
text-align: center;
padding: 20px;
}
ìë°ì¤í¬ë¦½í¸
ë§ì§ë§ì¼ë¡, Intersection Observer API를 ì¬ì©íì¬ ìì ì ìííë JavaScript ì½ë를 ì´í´ë´ ìë¤.
ì¤ë¹
첫째, ë³ì를 ì¤ë¹íê³ observer를 ì¤ì¹í´ì¼ í©ëë¤.
const numSteps = 20.0;
let boxElement;
let prevRatio = 0.0;
let increasingColor = "rgba(40, 40, 190, ratio)";
let decreasingColor = "rgba(190, 40, 40, ratio)";
// Set things up
window.addEventListener(
"load",
(event) => {
boxElement = document.querySelector("#box");
createObserver();
},
false,
);
ì¬ê¸°ì ì¤ì í ììì ë³ìë ë¤ìê³¼ ê°ìµëë¤.
numSteps-
ê°ìì± ë¹ì¨ì¸ 0.0ê³¼ 1.0 ì¬ì´ìì ëª ê°ì ìê³ê°ì ê°ì§ ì§ë¥¼ ëíë´ë ììì ëë¤.
prevRatio-
ì´ ë³ìë ìê³ê°ì´ ë§ì§ë§ì¼ë¡ ì´ê³¼ë ê°ìì± ë¹ì¨ì 기ë¡íë ë° ì¬ì©ë©ëë¤. ì´ë¥¼ íµí´ ëì ììê° ë ë§ì´ í¹ì ë ì ê² ë³´ì´ë ì§ë¥¼ ì ì ììµëë¤.
increasingColor-
ê°ìì± ë¹ì¨ì´ ì¦ê°í ë ëì ììì ì ì©í ìê¹ì ì ìíë 문ìì´ì ëë¤. 문ìì´ìì "ratio"ë¼ë ë¨ì´ë ëìì íì¬ ê°ìì± ë¹ì¨ë¡ ëì²´ë ê²ì´ê³ , ììë ììë§ ë³ííë ê²ì´ ìëë¼ ë 모í¸í´ì§ë©´ì ì ì°¨ ë ë¶í¬ëª í´ì§ëë¤.
decreasingColor-
ë¹ì·íê², ê°ìì± ë¹ì¨ì´ ê°ìí ë ì ì©í ììì ì ìí 문ìì´ì ëë¤.
load ì´ë²¤í¸ë¥¼ ìì ì ììí기 ìí´ Window.addEventListener()를 í¸ì¶í©ëë¤. íì´ì§ ë¡ë©ì´ ëëê³ ëë©´, querySelector()를 ì¬ì©íì¬ "box" ID를 ê°ì§ ììì ëí 참조를 ì»ê³ , ê³§ êµì°¨ ê´ì°°ì êµ¬ì¶ ë° ì¤ì¹ë¥¼ ì²ë¦¬í기 ìí´ ìì±í createObserver() ë©ìë를 í¸ì¶í©ëë¤.
êµì°¨ ê´ì°°ì ìì±
createObserver() ë©ìëë íì´ì§ ë¡ëê° ìë£ëìì ë í¸ì¶ëì´ ì¤ì ë¡ ìë¡ì´ IntersectionObserver를 ìì±íê³ ëì ìì를 ê´ì°°íë íë¡ì¸ì¤ë¥¼ ììí©ëë¤.
function createObserver() {
let observer;
let options = {
root: null,
rootMargin: "0px",
threshold: buildThresholdList(),
};
observer = new IntersectionObserver(handleIntersect, options);
observer.observe(boxElement);
}
ì´ë ê´ì°°ìì ëí ì¤ì ì í¬í¨íë options ê°ì²´ë¥¼ ì¤ì íë ê²ì¼ë¡ë¶í° ììí©ëë¤. 문ìì ë·°í¬í¸ë¥¼ 기ì¤ì¼ë¡ ëì ììì ê°ìì± ë³í를 ê´ì°°íë ¤ê³ íë¯ë¡ rootë null ì
ëë¤. ì¬ë°±ì íì ì기 ë문ì ì¬ë°± ì¤íì
ì¸ rootMarginì "0px"ë¡ ì§ì í©ëë¤. ì´ë ê´ì°°ìê° ëì ììì ê²½ê³ì ë·°í¬í¸ ì¬ì´ì ì´ë¤ ëí´ì§ (í¹ì ë¹ ì§) ê³µê° ìì´ êµì°¨ ë³í를 ê´ì°°íë ê²ì ì¼ê¸°í©ëë¤.
ê°ìì± ë¹ì¨ ìê³ê° 목ë¡ì¸ threshold ë buildThresholdList() í¨ì를 íµí´ ë§ë¤ì´ì§ëë¤. ìê³ê° 목ë¡ì ì´ ìììì ìê° ë§ê³ ê·¸ ì를 ì¡°ì í ì ìì¼ë¯ë¡ ê³íì ì¼ë¡ ë§ë¤ì´ì§ëë¤.
optionsê° ì¤ë¹ëë©´, IntersectionObserver() ìì±ì를 í¸ì¶íê³ , êµì°¨ ì§ì ì´ ìê³ê° ì¤ íë를 êµì°¨í ë í¸ì¶ë í¨ìì¸ handleIntersect()ì ìµì
ì ì§í©ì ì§ì íì¬ ìë¡ì´ ê´ì°°ì를 ìì±í©ëë¤. ê·¸ë¦¬ê³ ë°íë ê´ì°°ìì observe()를 í¸ì¶íì¬ ìíë ëì ììì ì ë¬í©ëë¤.
ìíë¤ë©´ ê° ììì ëí´ observer.observe()를 í¸ì¶íì¬ ë·°í¬í¸ì ëí ê°ìì± êµì°¨ ë³í를 ì¬ë¬ ìììì 모ëí°ë§í ì ìëë¡ ì íí ì ììµëë¤.
ìê³ê° ë¹ì¨ì ì§í© 구ì¶
ìê³ê° ì§í©ì ë§ëë buildThresholdList() í¨ìë ë¤ìê³¼ ê°ìµëë¤.
function buildThresholdList() {
let thresholds = [];
let numSteps = 20;
for (let i = 1.0; i <= numSteps; i++) {
let ratio = i / numSteps;
thresholds.push(ratio);
}
thresholds.push(0);
return thresholds;
}
ì´ë ê² íë©´ 1ê³¼ numSteps ì¬ì´ì ê° ì«ì iì ëí´ i/numSteps ê°ì thresholds ì§í©ì ë£ìì¼ë¡ì¨ 0.0ìì 1.0 ì¬ì´ì ë¹ì¨ì¸ ê° ìê³ê°ì ì§í©ì ë§ëëë¤. ëí ê·¸ ê°ì í¬í¨í기 ìí´ì 0ì ë£ìµëë¤. ê·¸ ê²°ê³¼, numSteps(20)ì 기본ê°ì ê³ ë ¤íì ë ìê³ê° ì§í©ì ë¤ìê³¼ ê°ìµëë¤.
| # | Ratio | # | Ratio |
|---|---|---|---|
| 0 | 0.05 | 11 | 0.6 |
| 1 | 0.1 | 12 | 0.65 |
| 2 | 0.15 | 13 | 0.7 |
| 3 | 0.2 | 14 | 0.75 |
| 4 | 0.25 | 15 | 0.8 |
| 5 | 0.3 | 16 | 0.85 |
| 6 | 0.35 | 17 | 0.9 |
| 7 | 0.4 | 18 | 0.95 |
| 8 | 0.45 | 19 | 1 |
| 9 | 0.5 | 20 | 0 |
| 10 | 0.55 |
ë¬¼ë¡ , ì½ë ë´ì ìê³ê° ì§í©ì íë ì½ë©í ì ìê³ , ì¬ë¬ë¶ì ë³´íµ ê·¸ë ê² ìì±íê² ë ê² ì ëë¤. ê·¸ë¬ë ì´ ìì ë ì¸ë¶í를 ì¡°ì í기 ìí´ êµ¬ì± ì ì´ë¥¼ ì¶ê°í기 ìí ê³µê°ì ë¨ê²¨ëììµëë¤.
êµì°¨ ë³í ì²ë¦¬
ëì ìì(ì´ ìì ìì IDê° "box"ì¸ ìì)ê° ê³µê°ëê±°ë ê°ë ¤ì ¸ì ê°ìì± ë¹ì¨ì´ ìê³ê° ì§í© ì¤ íë를 êµì°¨íë ê²ì ë¸ë¼ì°ì ê° ê°ì§í ë, ì²ë¦¬ í¨ìì¸ handleIntersect()를 í¸ì¶í©ëë¤.
function handleIntersect(entries, observer) {
entries.forEach((entry) => {
if (entry.intersectionRatio > prevRatio) {
entry.target.style.backgroundColor = increasingColor.replace(
"ratio",
entry.intersectionRatio,
);
} else {
entry.target.style.backgroundColor = decreasingColor.replace(
"ratio",
entry.intersectionRatio,
);
}
prevRatio = entry.intersectionRatio;
});
}
entries 목ë¡ì ìë ê° IntersectionObserverEntryì ëí´ ìí¸ë¦¬ì intersectionRatioê° ì¬ë¼ê°ê³ ìëì§ íì¸í©ëë¤. ë§ì½ ì¬ë¼ê°ê³ ìë¤ë©´, ëìì background-colorì increasingColor(기ìµíì¸ì. ììì "rgba(40, 40, 190, ratio)" ì
ëë¤.)ì 문ìì´ì ì¸í
íê³ , "ratio"ë¼ë ë¨ì´ë¥¼ ìí¸ë¦¬ì intersectionRatioë¡ ëì²´í©ëë¤. ê·¸ ê²°ê³¼ ììë§ ë³ííë ê² ìëë¼, ëì ììì í¬ëª
ëë ë³íí©ëë¤. ê°ìì± ë¹ì¨ì´ ê°ìíë©´, ë°°ê²½ ììì ìí ê°ì ê°ì´ ê°ìíë¯ë¡ ììê° ë í¬ëª
í´ì§ëë¤.
ë¹ì·íê², ë§ì½ intersectionRatio ê° ê°ìíë©´, decreasingColor 문ìì´ì ì¬ì©íê³ ëì ììì background-color 를 ì¤ì í기 ì ì "ratio"ë¼ë ë¨ì´ë¥¼ intersectionRatio ë¡ ëì²´í©ëë¤.
ê²°êµ, ê°ìì± ë¹ì¨ì´ ì¦ê°íëì§ ê°ìíëì§ë¥¼ ë°ë¼ê°ê¸° ìí´ì prevRatio ë³ìì ìë íì¬ ë¹ì¨ì 기ìµí´ì¼ í©ëë¤.
ê²°ê³¼
ìëë ê²°ê³¼ 컨í ì¸ ì ëë¤. íì´ì§ë¥¼ ììëë¡ ì¤í¬ë¡¤íê³ ìì§ìì ë°ë¼ ë°ì¤ 모ìì´ ì¼ë§ë ë³ííëì§ ììë³´ì¸ì.
ë ê´ë²ìí ìì ë ë¤ì ë§í¬ì ììµëë¤. Timing element visibility with the Intersection Observer API.
ëª ì¸ì
| Specification |
|---|
| Intersection Observer > # intersection-observer-interface > |