skip to Main Content

I have 3 blocks on the page.

On the second block, I have 3 cases (maybe more), there is also a background line, and there is a circle in the middle of the case on this line

.block1 {
  height: 200px;
  background-color: gray;
}

.block2 {
  height: 100%;
  background: linear-gradient(214deg, rgba(79, 142, 255, 0.00) 0%, #4F8EFF 10%, #F5E550 90%, rgba(79, 142, 255, 0.00) 100%) center / 3px calc(100% - 100px) no-repeat;
  
  .circle {
    position: relative;
    width: 15px;
    height: 15px;
    background-color: white;
    border: solid 3px #4F8EFF;
    border-radius: 50%;
    top: 50%;
    left: calc(50% - 8px);
  }
}

.text {
  text-align: center;
  padding: 200px 50px;
}

.block3 {
  height: 200px;
  background-color: gray;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css" integrity="sha512-t4GWSVZO1eC8BM339Xd7Uphw5s17a86tIZIj8qRxhnKub6WoyhnrxeCIMeAqBPgdZGlCcG2PrZjMc+Wr78+5Xg==" crossorigin="anonymous" referrerpolicy="no-referrer"
/>

<div class="block1"></div>

<div class="block2">
  <div class="case">
    <div class="row">
      <div class="col-5 text">Text 1</div>
      <div class="col-2">
        <div class="circle"></div>
       </div>
      <div class="col-5 text">Text 1</div>
    </div>
  </div>
  <div class="case">
    <div class="row">
      <div class="col-5 text">Text 2</div>
      <div class="col-2"></div>
      <div class="col-5 text">Text 2</div>
    </div>
  </div>
  <div class="case">
    <div class="row">
      <div class="col-5 text">Text 3</div>
      <div class="col-2"></div>
      <div class="col-5 text">Text 3</div>
    </div>
  </div>
</div>

<div class="block3"></div>

Right now this circle is only for the first case, inside <div class="col-2">

Is it possible to make it so that, depending on the page scroll, this circle moves through all cases, and becomes empty <div class="col-2">, just like I drew. And it is important that the color of this circle is the same as the color of the line

That is, if we are in the middle of the page of the first case, then the circle should be on it, if we moved lower to the second case, then the circle should accordingly move to the second case, while I would like the circle itself to slide along with the scroll, and when scroll stop moved to the nearest case

enter image description here

2

Answers


  1. This should be more a comment then an answer… Here is how I would play with scroll, but color change is missing.

    Oh! And you should give to .col-2 some sort of ID to improve filtering on circle movement!

    $(document).on('scroll', function() {
      const offset = 0;
      let $circle = $('.circle');
      $('.case').each(function() {
        if(window.scrollY > ($(this).offset().top - offset)) {
          $(this).find('.col-2').append($circle);
        }
      });
    });
    .block1 {
      height: 200px;
      background-color: gray;
    }
    
    .block2 {
      height: 100%;
      background: linear-gradient(214deg, rgba(79, 142, 255, 0.00) 0%, #4F8EFF 10%, #F5E550 90%, rgba(79, 142, 255, 0.00) 100%) center / 3px calc(100% - 100px) no-repeat;
      
      .circle {
        position: relative;
        width: 15px;
        height: 15px;
        background-color: white;
        border: solid 3px #4F8EFF;
        border-radius: 50%;
        top: 50%;
        left: calc(50% - 8px);
      }
    }
    
    .text {
      text-align: center;
      padding: 200px 50px;
    }
    
    .block3 {
      height: 200px;
      background-color: gray;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css" integrity="sha512-t4GWSVZO1eC8BM339Xd7Uphw5s17a86tIZIj8qRxhnKub6WoyhnrxeCIMeAqBPgdZGlCcG2PrZjMc+Wr78+5Xg==" crossorigin="anonymous" referrerpolicy="no-referrer"
    />
    
    <div class="block1"></div>
    
    <div class="block2">
      <div class="case">
        <div class="row">
          <div class="col-5 text">Text 1</div>
          <div class="col-2">
            <div class="circle"></div>
           </div>
          <div class="col-5 text">Text 1</div>
        </div>
      </div>
      <div class="case">
        <div class="row">
          <div class="col-5 text">Text 2</div>
          <div class="col-2"></div>
          <div class="col-5 text">Text 2</div>
        </div>
      </div>
      <div class="case">
        <div class="row">
          <div class="col-5 text">Text 3</div>
          <div class="col-2"></div>
          <div class="col-5 text">Text 3</div>
        </div>
      </div>
    </div>
    
    <div class="block3"></div>
    Login or Signup to reply.
  2. I moved .circle out of .case so we only need to change its top.

    detectCase() will find out which .case is closest to .circle

    handleScroll() will change .circle‘s top & backgroundPosition so its position and color will change while scroll.

    const circle = document.querySelector(".circle");
    const cases = document.querySelectorAll(".case");
    let timer = null;
    
    const detectCase = () => {
      const circleCenter = circle.offsetTop + circle.offsetHeight / 2;
      let activeCase = null,
        minDist = Infinity;
      cases.forEach((elem) => {
        const caseCenter = elem.offsetTop + elem.offsetHeight / 2;
        const dist = Math.abs(caseCenter - circleCenter);
        if (dist < minDist) {
          minDist = dist;
          activeCase = elem;
        }
      });
      return activeCase;
    };
    
    const handleScroll = () => {
      const {
        height: blockHeight
      } = document.querySelector(".block2").getBoundingClientRect();
      const maxTop = cases[cases.length - 1].offsetTop;
      const minTop = cases[0].offsetTop;
      let {
        height: startTop
      } = cases[0].getBoundingClientRect();
      let scrollDist = startTop / 2 + window.scrollY;
      scrollDist = scrollDist > maxTop ? maxTop : scrollDist < minTop ? minTop : scrollDist;
      circle.style.top = `${scrollDist}px`;
      circle.style.backgroundSize = `15px ${blockHeight}px`;
      circle.style.backgroundPosition = `0 ${-scrollDist}px`;
      if (timer) return;
      timer = setTimeout(() => {
        const active = detectCase();
        const activePos = active.offsetTop + active.offsetHeight / 2;
        circle.style.top = `${activePos}px`;
        circle.style.backgroundPosition = `0 ${-activePos}px`;
        circle.style.transition = "0.5s";
        timer = null;
      }, 800);
      circle.style.transition = "";
    };
    
    handleScroll();
    window.addEventListener("scroll", handleScroll);
    .block1,
    .block3 {
      height: 200px;
      background-color: gray;
    }
    
    .block2 {
      height: 100%;
      position: relative;
    }
    
    .block2,
    .block2 .circle {
      background: linear-gradient(214deg, rgba(79, 142, 255, 0) 0%, #4f8eff 10%, #f5e550 90%, rgba(79, 142, 255, 0) 100%) center/3px calc(100% - 100px) no-repeat;
    }
    
    .block2 .circle {
      width: 15px;
      height: 15px;
      left: calc(50% - 8px);
    }
    
    .block2 .circle,
    .block2 .circle::before {
      position: absolute;
      border-radius: 50%;
    }
    
    .block2 .circle::before {
      content: "";
      inset: 3px;
      background-color: white;
    }
    
    .text {
      text-align: center;
      padding: 200px 50px;
    }
    
    
    /*# sourceMappingURL=so.css.map */
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css" integrity="sha512-t4GWSVZO1eC8BM339Xd7Uphw5s17a86tIZIj8qRxhnKub6WoyhnrxeCIMeAqBPgdZGlCcG2PrZjMc+Wr78+5Xg==" crossorigin="anonymous" referrerpolicy="no-referrer"
    />
    <div class="block1"></div>
    <div class="block2">
      <div class="circle"></div>
      <div class="case">
        <div class="row">
          <div class="col-5 text">Text 1</div>
          <div class="col-2"></div>
          <div class="col-5 text">Text 1</div>
        </div>
      </div>
      <div class="case">
        <div class="row">
          <div class="col-5 text">Text 2</div>
          <div class="col-2"></div>
          <div class="col-5 text">Text 2</div>
        </div>
      </div>
      <div class="case">
        <div class="row">
          <div class="col-5 text">Text 3</div>
          <div class="col-2"></div>
          <div class="col-5 text">Text 3</div>
        </div>
      </div>
    </div>
    <div class="block3"></div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search