5 . ๐Ÿš€ Intersection Observer

๋„ฅ์ŠคํŠธ๋กœ ๋งŒ๋“  ํ”„๋กœ์ ํŠธ์—์„œ ์Šคํฌ๋กค๊ฐ’์— ๋”ฐ๋ผ์„œ ํ•ด๋”๊ฐ€๋‹ค๋ฅด๊ฒŒ ๋‹ค๋ฅด๊ฒŒ ๊ตฌํ˜„ํ–ˆ๋Š”๋ฐ ์Šคํฌ๋กค ์ด๋ฒคํŠธ์— ๋Œ€ํ•ด์„œ ์ซŒ ๊ณต๋ถ€ํ•ด๋ณผ ํ•„์š”๊ฐ€ ์žˆ๋Š” ๊ฒƒ ๊ฐ™์•„์„œ intersection Observer์— ๋Œ€ํ•ด์„œ ๊ณต๋ถ€ํ•ด๋ณด๋ ค๊ณ  ํ•œ๋‹ค.

โœจ Intersection Observer

โ“ Intersection Observer๋ž€

  • Intersection observer๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ธŒ๋ผ์šฐ์ € ๋ทฐํฌํŠธ(Viewport)์™€ ์„ค์ •ํ•œ ์š”์†Œ(Element)์˜ ๊ต์ฐจ์ ์„ ๊ด€์ฐฐํ•˜๋ฉฐ, ์š”์†Œ๊ฐ€ ๋ทฐํฌํŠธ์— ํฌํ•จ๋˜๋Š”์ง€ ํฌํ•จ๋˜์ง€ ์•Š๋Š”์ง€, ๋” ์‰ฝ๊ฒŒ๋Š” ์‚ฌ์šฉ์ž ํ™”๋ฉด์— ์ง€๊ธˆ ๋ณด์ด๋Š” ์š”์†Œ์ธ์ง€ ์•„๋‹Œ์ง€๋ฅผ ๊ตฌ๋ณ„ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค.
  • ์ด ๊ธฐ๋Šฅ์€ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์‹คํ–‰๋˜๋ฉฐ, scroll ๊ฐ™์€ ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜์˜ ์š”์†Œ ๊ด€์ฐฐ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ Œ๋”๋ง ์„ฑ๋Šฅ์ด๋‚˜ ์ด๋ฒคํŠธ ์—ฐ์† ํ˜ธ์ถœ ๊ฐ™์€ ๋ฌธ์ œ ์—†์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

โ—ผ Intersection Observer ์‚ฌ์šฉ์ด์œ 

  • ์‚ฌ์šฉ์ด์œ ๋ฅผ ์‚ดํŽด๋ณด๊ธฐ ์ „ Intersection์ด๋ผ๋Š” ์˜๋ฏธ์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณผ ํ•„์š”๊ฐ€ ์žˆ๋‹ค. Intersection์ด๋ž€ ๊ต์ฐจ์ ,๊ต์ง‘ํ•ฉ์ด๋ผ๋Š” ์˜๋ฏธ๋ฅผ ๊ฐ–๊ณ  ์žˆ๋‹ค.

  • intersection observer๋Š” ๊ต์ฐจ์ ์„ ๊ด€์ธกํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” API๋ผ๋Š” ์˜๋ฏธ๋ฅผ ๊ฐ–๊ณ  ์žˆ๋Š”๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

    ์ฆ‰, Target Element ๊ฐ€ ํ™”๋ฉด์— ๋…ธ์ถœ๋˜์—ˆ๋Š” ์ง€ ์—ฌ๋ถ€๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌ๋…ํ•  ์ˆ˜ ์žˆ๋Š” API ์ด๋‹ค.

    ์˜ˆ๋ฅผ ๋“ค์–ด, intersection observer๊ฐ€ ์—†์ด ๊ตฌํ˜„ํ•œ๋‹ค๊ณ  ํ•œ๋‹ค๋ฉด, scroll์ด ์ผ์–ด๋‚  ๋•Œ ๋งˆ๋‹ค, ํŠน์ • element๊ฐ€ ํ™”๋ฉด์— ์กด์žฌํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ์—ฌ๋ถ€๋ฅผ ๊ณ„์† ๊ณ„์‚ฐํ•˜๋Š” code๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค. ํ•˜์ง€๋งŒ intersection์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์‰ฝ๊ฒŒ ์‚ฌ์šฉ์—ฌ๋ถ€๋ฅผ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค.


โ—ผ MDN์—์„œ ์ œ์•ˆํ•œ ์ ์šฉ ์ƒํ™ฉ๋“ค

1. ํŽ˜์ด์ง€ ์Šคํฌ๋กค ์‹œ ์ด๋ฏธ์ง€๋ฅผ Lazy Loadingํ•  ๋•Œ
2. Infinite scrolling์„ ํ†ตํ•ด ์Šคํฌ๋กค์„ ํ•˜๋ฉฐ ์ƒˆ๋กœ์šด ์ฝ˜ํ…์ธ ๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ๋•Œ
3. ๊ด‘๊ณ ์˜ ์ˆ˜์ต์„ ๊ณ„์‚ฐํ•˜๊ธฐ ์œ„ํ•ด ๊ด‘๊ณ ์˜ ๊ฐ€์‹œ์„ฑ์„ ์ฐธ๊ณ ํ•  ๋•Œ
4. ์‚ฌ์šฉ์ž๊ฐ€ ๊ฒฐ๊ณผ๋ฅผ ๋ณผ ๊ฒƒ์ธ์ง€์— ๋”ฐ๋ผ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋™์ž‘ ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •ํ•  ๋•Œ

  • Lazy Loading์ด๋ž€?
    - ํŽ˜์ด์ง€๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์‹œ์ ์— ๋‹น์žฅ ํ•„์š”ํ•˜์ง€ ์•Š์€ ๋ฆฌ์†Œ์Šค๋“ค์„ ์ถ”ํ›„์— ๋กœ๋”ฉํ•˜๊ฒŒ ํ•˜๋Š” ๊ธฐ์ˆ . ์ฆ‰, ์‚ฌ์šฉ์ž๊ฐ€ ๋ณด์ง€ ์•Š์„๋•Œ๋Š” ๋‹น์žฅ ๋กœ๋”ฉํ•˜์ง€ ์•Š๊ณ , ๋‚˜์ค‘์— ์‚ฌ์šฉ์ž๊ฐ€ ํ•„์š”๋กœ ํ•˜๋Š” ์‹œ์ ์— ๋กœ๋”ฉํ•˜๋Š” ๊ธฐ์ˆ 
    - infinite scrolling ๊ณผ placeholder๊ฐ€ Lazy Loading์˜ ์˜ˆ์‹œ

โ—ผ Intersection Observer ์ƒ์„ฑ, API

intersection observer๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ƒ์„ฑ์ž ํ˜ธ์ถœ ์‹œ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ œ๊ณตํ•ด์•ผ ํ•œ๋‹ค. ์ด ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋Š” threshold๊ฐ€ ํ•œ ๋ฐฉํ–ฅ ํ˜น์€ ๋‹ค๋ฅธ ๋ฐฉํ–ฅ์œผ๋กœ ๊ต์ฐจํ•  ๋•Œ ์‹คํ–‰๋œ๋‹ค.

const observer= new IntersectionObserver(callback,options)

โ—ผ callback


const intersectionObserver = new IntersectionObserver((entries, observer) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      console.log(entry);
      observer.unobserve(entry.target);
    }
  });
});
intersectionObserver.observe(document.getElementById("app"));

โ—พ entries

entries๋Š” IntersectionObserverEntry ์ธ์Šคํ„ด์Šค์˜ ๋ฐฐ์—ด์ด๋‹ค.
IntersectionObserverEntry๋Š” ์ฝ๊ธฐ ์ „์šฉ(Read only)์˜ ๋‹ค์Œ ์†์„ฑ๋“ค์„ ํฌํ•จํ•œ๋‹ค.

  • boundingClientRect(DOMRectReadOnly): ๊ด€์ฐฐ ๋Œ€์ƒ์˜ ์‚ฌ๊ฐํ˜• ์ •๋ณด
  • intersectionRect(DOMRectReadOnly): ๊ด€์ฐฐ ๋Œ€์ƒ์˜ ๊ต์ฐจํ•œ ์˜์—ญ ์ •๋ณด
  • intersectionRatio: ๊ด€์ฐฐ ๋Œ€์ƒ์˜ ๊ต์ฐจํ•œ ์˜์—ญ ๋ฐฑ๋ถ„์œจ(intersectionRect ์˜์—ญ์—์„œ boundingClientRect ์˜์—ญ๊นŒ์ง€ ๋น„์œจ, Number)
  • isIntersecting(Boolean): ๊ด€์ฐฐ ๋Œ€์ƒ์˜ ๊ต์ฐจ ์ƒํƒœ
  • rootBounds(DOMRectReadOnly): ์ง€์ •ํ•œ ๋ฃจํŠธ ์š”์†Œ์˜ ์‚ฌ๊ฐํ˜• ์ •๋ณด
  • target(Element): ๊ด€์ฐฐ ๋Œ€์ƒ ์š”์†Œ

โ—พ observer

  • ์ฝœ๋ฐฑ์ด ์‹คํ–‰๋˜๋Š” ํ•ด๋‹น ์ธ์Šคํ„ด์Šค๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค.

โ—ผ options


let options={
	root: document.querySelector('#target'),
    	rootMargin:'0px',
    	threshold:1.0
}
let observer = new IntersectionObserver(callback, options);

โ—พ root

  • ํƒ€๊ฒŸ์˜ ๊ฐ€์‹œ์„ฑ์„ ๊ฒ€์‚ฌํ•˜๊ธฐ ์œ„ํ•ด ๋ทฐํฌํŠธ ๋Œ€์‹  ์‚ฌ์šฉํ•  ์š”์†Œ ๊ฐ์ฒด๋ฅผ ์ง€์ •ํ•œ๋‹ค.
    ํƒ€๊ฒŸ์˜ ์กฐ์ƒ ์š”์†Œ์ด์—ฌ์•ผ ํ•˜๋ฉฐ, ์ง€์ •ํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ null์ผ ๊ฒฝ์šฐ ๋ธŒ๋ผ์šฐ์ €์˜ ๋ทฐํฌํŠธ๊ฐ€ ๊ธฐ๋ณธ ์‚ฌ์šฉ๋œ๋‹ค.

โ—พ rootMargin

  • ๋ฐ”๊นฅ ์—ฌ๋ฐฑ(Margin)์„ ์ด์šฉํ•ด Root ๋ฒ”์œ„๋ฅผ ํ™•์žฅํ•˜๊ฑฐ๋‚˜ ์ถ•์†Œํ•  ์ˆ˜ ์žˆ๋‹ค.
    CSS์˜ margin๊ณผ ๊ฐ™์ด 4๋‹จ๊ณ„๋กœ ์—ฌ๋ฐฑ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, px ๋˜๋Š” %๋กœ ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์€ 0px 0px 0px 0px์ด๋ฉฐ ๋‹จ์œ„๋ฅผ ๊ผญ ์ž…๋ ฅํ•ด์•ผ ํ•œ๋‹ค.

โ—พ threshold

  • observer์˜ ์ฝœ๋ฐฑ์ด ์‹คํ–‰๋  ๋Œ€์ƒ์˜ ๊ฐ€์‹œ์„ฑ %๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๋‹จ์ผ์ˆซ์ž, ๋ฐฐ์—ด์ด๋‹ค.
    ๋งŒ์•ฝ 50% ๋งŒํผ์˜ ์š”์†Œ๊ฐ€ ๋ณด์—ฌ์กŒ์„ ๋•Œ๋ฅผ ํƒ์ง€ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด 0.5๋กœ ์„ค์ •ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.
    ๊ธฐ๋ณธ๊ฐ’์€ 0์ด๋ฉฐ, 1.0์€ ์š”์†Œ์˜ ๋ชจ๋“  ํ”ฝ์…€์ด ํ™”๋ฉด์— ๋…ธ์ถœ๋˜๊ธฐ ์ „์—๋Š” ์ฝœ๋ฐฑ์‹œํ‚ค์ง€ ์•Š์Œ์„ ์˜๋ฏธํ•œ๋‹ค.

โ—ป Method


const observer= new InterSectionObserver((entries) => {
	entries.forEach(entry => console.log(entry))
},{threshold:0.3});
const target= document.querySelector('#element');
oberver.observe(target) //  ๊ด€์ฐฐ์‹œ์ž‘
observer.unobserver(target) //  ๊ด€์ฐฐ ์ค‘์ง€
observer.disconnect() // IntersectionObserver ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ด€์ฐฐํ•˜๋Š” ๋ชจ๋“  ์š”์†Œ ๊ด€์ฐฐ ์ค‘์ง€

โ—พ observer : ๋Œ€์ƒ ์š”์†Œ์˜ ๊ด€์ฐฐ์„ ์‹œ์ž‘ํ•œ๋‹ค.

  • parameter : IntersectionObserver ํƒ€๊ฒŸ

โ—พ unobserver : ๋Œ€์ƒ ์š”์†Œ์˜ ๊ด€์ฐฐ์„ ๋ฉˆ์ถ˜๋‹ค.

  • parameter : IntersectionObserver ํƒ€๊ฒŸ
  • ์ฝœ๋ฐฑ์˜ ๋‘๋ฒˆ์งธ ์ธ์ž๊ฐ€ observer๊ฐ€ ํ•ด๋‹น ์ธ์Šคํ„ดํŠธ๋ฅผ ์ฐธ๊ณ ํ•˜๋ฏ€๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉ ๊ฐ€๋Šฅ.
const observer= new InterSectionObserver((entries,observer) => {
	entries.forEach(entry => {
    	if(!entry.isIntersection){
        return false;
        //๊ต์ฐจ ์ƒํƒœ๊ฐ€ ์•„๋‹ ๋•Œ return
        }
        //๊ด€์ฐฐ๋Œ€์ƒ์ด ๊ต์ฐจ์ƒํƒœ์ผ๋•Œ๋งŒ ์‹คํ–‰
        console.log('๊ต์ฐจ์ƒํƒœ ํ™•์ธ:',entry.isIntersection);
        //์œ„ ์‹คํ–‰์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ๊ด€์ฐฐ ์ค‘์ง€.
        observer.unobserve(entry.target);
    })
},{threshold:0.3});

โ—พ disconnect() : IntersectionObserver ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ด€์ฐฐํ•˜๋Š” ๋ชจ๋“  ์š”์†Œ์˜ ๊ด€์ฐฐ์„ ์ค‘์ง€ํ•œ๋‹ค.

  • paramteter: ์—†์Œ.

๐ŸŽ‰ ๊ฒฐ๋ก 

  • ๋ณดํ†ต scroll event๊ฐ€ ์‹คํ–‰๋˜๊ฒŒ ๋˜๋ฉด ์Šคํฌ๋กค์ด ์ผ์–ด๋‚ ๋•Œ๋งˆ๋‹ค ๋ฐœ์ƒ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์Šคํฌ๋กค์„ ๋‚ด๋ฆด ๋•Œ ๋งˆ๋‹ค ์‹คํ–‰๋œ๋‹ค. ๊ทธ๋ž˜์„œ ํ•ด๋”๋ถ€๋ถ„์„ ๋‹ค๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•˜๊ฑฐ๋‚˜ ์Šคํฌ๋กค ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์‹คํ–‰ํ•  ๋•Œ ๋ถˆํ•„์š”ํ•œ ์ด๋ฒคํŠธ๊ฐ€ ๋งŽ์ด ๋ฐœ์ƒ๋˜๊ฒŒ ๋œ๋‹ค.
  • Intersection Observer๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด viewport ๊ธฐ์ค€์œผ๋กœ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒ๋˜๊ณ , ๊ธฐ์ค€์œผ๋กœ ํ•  ํƒ์ƒ‰ ํ•  ํƒ€๊ฒŸ์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๊ธฐ๋•Œ๋ฌธ์— ๋ถˆํ•„์š”ํ•œ ์ด๋ฒคํŠธ๊ฐ€ ์ผ์–ด๋‚˜์ง€ ์•Š๋Š”๋‹ค.
  • ์†”์งํžˆ ํŽ˜์ด์ง€๋ฅผ ์„œ๋ฒ„์— ๋ฐฐํฌํ•ด๋ณธ์ ์ด ์—†์–ด์„œ ์ด๋ฒคํŠธ๊ฐ€ ๋งŽ์ด ์ผ์–ด๋‚˜์„œ ์ƒ๊ธฐ๋Š” ์ด์Šˆ์™€ ์•ฝ์ ๋“ค์„, dev๋ชจ๋“œ์—์„œ๋Š” ์†๋„์ฐจ์ด๊ฐ€ ํฌ๊ฒŒ ๋‚˜์ง€ ์•Š๊ธฐ๋•Œ๋ฌธ์— ํฌ๊ฒŒ ๋Š๋‚„ ์ˆ˜ ์—†์—ˆ๋‹ค. ํ•˜์ง€๋งŒ ํ”„๋กœ์ ํŠธ์˜ ์‚ฌ์ด์ฆˆ๊ฐ€ ์ปค์ง„๋‹ค๋ฉด ์ด ๋ถ€๋ถ„์€ ํฐ ์ด์Šˆ๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐ๋œ๋‹ค.
    ๋‹ค์Œ ํฌ์ŠคํŒ…์€ IntersectionObserver๋ฅผ ์‚ฌ์šฉํ•œ ๋ฌดํ•œ ์Šคํฌ๋กค ๊ตฌํ˜„ํ•˜๊ธฐ!

์ถœ์ฒ˜

์ข‹์€ ์›นํŽ˜์ด์ง€ ์ฆ๊ฒจ์ฐพ๊ธฐ