<div class="allContainer">
    <h3>threshold: 0</h3>
    <div class="outerContainer">
      <div class="container1">
        <div class="msg1"></div>
        <div class="box1"></div>
      </div>
    </div>
    <h3>threshold: 0.5</h3>
    <div class="outerContainer">
      <div class="container2">
        <div class="msg2"></div>
        <div class="box2"></div>
      </div>
    </div>
    <h3>threshold: 1.0</h3>
    <div class="outerContainer">
      <div class="container3">
        <div class="msg3"></div>
        <div class="box3"></div>
      </div>
    </div>
  </div>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.allContainer {
  width: 100%;
  display: flex;
  flex-flow: column;
  align-items: center;
  padding: 2rem 0;
}

.outerContainer {
  position: relative;
  width: 300px;
  height: 300px;
  border: 1px solid black;
}

.container1, .container2, .container3 {
  width: 300px;
  height: 300px;
  overflow: auto;
}

h3 {
  margin: 1rem 0;
}

.msg1, .msg2, .msg3{
  text-transform: capitalize;
  position: absolute;
  top: 50%;
  left: 1rem;
  font-size: x-large;
  transform: translate3d(0, -50%, 0);
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #fff;
  font-family: Arial, Helvetica, sans-serif;
}

.box1, .box2, .box3 {
  margin: 500px auto;
  width: 150px;
  height: 150px;
  background-color: blue;
  transition: background-color 2s;
}

.active {
  background-color: red;
}
const container1 = document.querySelector(".container1")
const container2 = document.querySelector(".container2")
const container3 = document.querySelector(".container3")
const box1 = document.querySelector(".box1")
const box2 = document.querySelector(".box2")
const box3 = document.querySelector(".box3")
const msg1 = document.querySelector(".msg1")
const msg2 = document.querySelector(".msg2")
const msg3 = document.querySelector(".msg3")

const observer1 = new IntersectionObserver((entries, observer) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      entry.target.classList.add("active")
      msg1.innerHTML = "box has entered"
    } else {
      msg1.innerHTML = "box has left"
      entry.target.classList.remove("active")
    }
  })
}, {
  root: container1,
  threshold: 0,
})
observer1.observe(box1)

const observer2 = new IntersectionObserver((entries, observer) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      entry.target.classList.add("active")
      msg2.innerHTML = "box has entered"
    } else {
      msg2.innerHTML = "box has left"
      entry.target.classList.remove("active")
    }
  })
}, {
  root: container2,
  threshold: 0.5,
})
observer2.observe(box2)

const observer3 = new IntersectionObserver((entries, observer) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      entry.target.classList.add("active")
      msg3.innerHTML = "box has entered"
    } else {
      msg3.innerHTML = "box has left"
      entry.target.classList.remove("active")
    }
  })
}, {
  root: container3,
  threshold: 1.0,
})
observer3.observe(box3)

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.