스크롤을 내렸을 때 나타나는 이미지

UI

  • intersectionObserver

2023-05-10 07:54

✍🏻 Table Of Contents

intersectionObserver API

  • 요소가 유저의 뷰포트에 들어왔는지, 숨겨졌는지 탐지
  • 지연 로딩 이미지, 애니메이션 발동, 유저의 활동 추적 등에 용

사용법

const observer = new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        // 요소가 50% 이상 보일 대 행하는 동작
      }
    })
  }, { threshold: 0.5 })

let element = document.querySelector('#my-element');
observer.observe(element);
javascript
  • 요소가 화면에 들어오거나 나갈 때 실행될 콜백 함수를 넘겨 IntersectionObserver 객체를 만든다.
  • 관찰하고 싶은 요소를 인자로, IntersectionObserver 객체의 observe 메소드를 호출하여 관찰을 시작한다.
  • 콜백 함수의 단일 인자인 entries(요소의 노출 정도, 위치, 크기 등 포함)로 필요한 정보를 얻는다.
const observer = new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        entry.boundingClientRect // 관찰된 요소의 뷰포트 내 위치와 크기
				entry.intersectionRatio // 관찰된 요소의 총 교차 (화면 노출) 비율
				entry.intersectionRect // 뷰포트 내 교차된 영역의 위치와 크기
				entry.isIntersecting // 뷰포트와 현재 교차되고 있는지를 나타내는 boolean
				entry.rootBounds // root 요소의 위치와 크기
				entry.target // 관찰되고 있는 대상 DOM 요소
				entry.time // 교차가 마지막으로 확인된 시
      }
    })
  }, { threshold: 0.5 })
javascript

결과물

html

<section class="poster hidden-area">
    <div class="poster__parallax">
      <div id="poster-image_wrapper_1" class="poster-image_wrapper">
        <img id="poster-image_1"
          src="https://github.com/Han-Kyeol/interactive-web-lecture/blob/main/interactive_web_code/Chapter%205/images/posterImages/poster_image_1.png?raw=true"
          alt="" class="poster-image">
      </div>
      <div id="poster-image_wrapper_2" class="poster-image_wrapper">
        <img id="poster-image_2"
          src="https://github.com/Han-Kyeol/interactive-web-lecture/blob/main/interactive_web_code/Chapter%205/images/posterImages/poster_image_2.png?raw=true"
          alt="" class="poster-image">
      </div>
      <div id="poster-image_wrapper_3" class="poster-image_wrapper">
        <img id="poster-image_3"
          src="https://github.com/Han-Kyeol/interactive-web-lecture/blob/main/interactive_web_code/Chapter%205/images/posterImages/poster_image_3.png?raw=true"
          alt="" class="poster-image">
      </div>
    </div>
  </section>
html

css

.poster__parallax {
  position: relative;
  height: 1500px;
}

.poster-image {
  position: absolute;
  opacity: 0;
}

.poster-image_wrapper {
  position: absolute;
  width: 100%;
}

#poster-image_wrapper_1 {
  right: 0;
  height: 100%;
}

#poster-image_wrapper_2 {
  top: 10%;
  left: 5%;
  height: 667px;
}

#poster-image_wrapper_3 {
  top: 35%;
  right: 0;
  height: 772px;
}

#poster-image_1 {
  right: 0;
  width: 1127px;
}

#poster-image_2 {
  height: 100%;
}

#poster-image_3 {
  right: 0;
  height: 100%;
}

@keyframes appear-right-to-left {
  from {
    opacity: 0;
    transform: translateX(100%);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes appear-left-to-right {
  from {
    opacity: 0;
    transform: translateX(-100%);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes appear-bottom-to-top {
  from {
    opacity: 0;
    transform: translateY(100%);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.poster-image_state_visible #poster-image_1 {
  animation: appear-right-to-left 0.75s ease;
  animation-fill-mode: forwards;
}

.poster-image_state_visible #poster-image_2 {
  animation: appear-left-to-right 0.75s ease;
  animation-fill-mode: forwards;
}

.poster-image_state_visible #poster-image_3 {
  animation: appear-bottom-to-top 0.75s ease;
  animation-fill-mode: forwards;
}
css

javascript

const observer = new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        entry.target.classList.add("poster-image_state_visible")
      }
    })
  }, { threshold: 0.2 })

  document.querySelectorAll(".poster-image_wrapper").forEach((poster) => {
    observer.observe(poster)
  })

  const posterParallax = document.querySelector(".poster__parallax")

  posterParallax.addEventListener("mousemove", (e) => {
    const xRelativeToPosterParallax = e.clientX / posterParallax.clientWidth
    const yRelativeToPosterParallax = e.clientY / posterParallax.clientHeight

    document.querySelector("#poster-image_wrapper_2").style.transform = `translate(${xRelativeToPosterParallax * -40}px, ${yRelativeToPosterParallax * -40}px)`
    document.querySelector("#poster-image_wrapper_3").style.transform = `translate(${xRelativeToPosterParallax * 40}px, ${yRelativeToPosterParallax * 40}px)`
  })
javascript