Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change Video on Scroll

I have taken the source code from this codepen page. It changes the image on scroll, but instead of image, I want to change the video on scroll.

Here is the code I have so far. The first video plays but it won't change on scroll. I added id="mainImage" in the Video Source tag, so it should work? What am I doing wrong?

CSS

.mouse_scroll {
  overflow: visible;
  position: relative;
}
.side_sec {
  display: flex;
}
.img-links div.text-sec {
  text-align: left;
  padding: 10px 20px;
  border-radius: 10px;
  margin: 500px 0px;
  background: transparent;
}
.img-links div.active {
  border: none;
  background: var(--box-bg-color);
}
.featured-img::before {
  content: "";
  position: absolute;
  background-size: 60%;
  background-repeat: no-repeat;
  background-position: left;
  left: 15%;
  right: 0px;
  top: -50px;
  width: 100%;
  height: 100%;
  z-index: 1;
  margin-right: 0px;
}
.featured-img {
  position: sticky;
  top: 140px;
  height: 700px;
}
.featured-img img {
  position: absolute;
  left: 75px;
  top: 35px;
  width: 55%;
  height: auto;
  border-radius: 30px;
}
.side-text {
  display: flex;
}
.side-text h3{
  color:orange;
}
.side-text p{
  color:#000;
}
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"  crossorigin="anonymous"></script>
<section id="videoonscroll">
  <div class="container">
    <div class="row">
      <div class="side-text">
        <div class="col-xl-7 col-lg-7 col-md-12 col-sm-12 col-12">
          <div class="img-links">
            <div data-src="video1.mp4" class="text-sec active">
              <h3 class="margin-10px-bottom">Better writing,<br>better results</h3>
              <p class="text-16 width-90">Be perfectly professional, clear, and convincing in a few clicks, not a few hours.</p>
            </div>
            <div class="text-sec" data-src="video2.mp4">
              <h3 class="margin-10px-bottom">The right text<br>for the context</h3>
              <p class="text-16 width-90">Get personalized suggestions based on what you’re writing and who will read it.</p>
            </div>
            <div class="text-sec" data-src="video3.mp4">
              <h3 class="margin-10px-bottom">Works where<br>you work</h3>
              <p class="text-16 width-90">Grammarly works across all the apps and sites you use. No copying, no pasting, no context switching.</p>
            </div>
            <div class="text-sec" data-src="video4.mp4">
              <h3 class="text-25 font-weight-700 margin-10px-bottom">Never go out of style</h3>
              <p class="text-16 width-90">Grammarly understands both your personal style and your brand style guide to help you find your voice.</p>
            </div>
            <div class="text-sec" data-src="video5.mp4">
              <h3 class="text-25 font-weight-700 margin-10px-bottom">This is responsible AI</h3>
              <p class="text-16 width-90">Don’t compromise on security. We never sell your data, provide it for advertising purposes, or allow third parties to use it to train their models.</p>
            </div>
            <!-- Add more divs as needed -->
          </div>
        </div>
        <div class="col-xl-5 col-lg-5 col-md-12 col-sm-12 col-12 sm-display-none">
          <div class="featured-img">
            <video class="video-player_video__8GR5s" autoplay="" loop="" muted="" playsinline="" poster="video1.png">
              <source src="video1.mp4" type="video/mp4" data-component-name="default-render-source" id="mainImage" />
            </video>
          </div>
        </div>
      </div>
    </div>
  </div>
</section>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/js/bootstrap.min.js'></script>

Javascript

$(document).ready(function () {
  // Function to handle mouse wheel events
  function handleMouseWheel(ele) {
    // Your logic here
    console.log("Mouse wheel event detected!");
    $('.img-links div.text-sec').removeClass('active');
    $(ele).addClass('active');
    // Update the main image based on the active div
    var newImageSrc = $(ele).data('src');
    $('#mainImage').attr('src', newImageSrc);
  }
  const options = { threshold: 0.4 };
  // Set up Intersection Observer
  const observer = new IntersectionObserver((entries, observer) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        // Add scroll event listener when target element is visible
        $(window).on('wheel', () => handleMouseWheel(entry.target));
      } else {
        // Remove scroll event listener when target element is not visible
        $(window).off('wheel', () => handleMouseWheel(entry.target));
      }
    });
  }, options);
  // Define the target elements you want to observe
  const targetElements = $('.img-links div.text-sec');
  // Start observing each target element
  targetElements.each(function () {observer.observe(this);});
});
like image 636
Toshi W Avatar asked Dec 06 '25 03:12

Toshi W


1 Answers

I'd like to address some issues in your code first:

  • You're importing bootstrap JS twice. No need to. Just use the the one before the closing </body> tag
  • Cache your Elements collections if you plan to reuse them often
  • Makes no sense to use the IntersectionObserver APi in combination with "scroll" events. Use just IntersectionObserver
  • Create a let variable elTextSecCurrent to store the currently active Element, in order to not reapply some logic on the already active one
  • Inside the observer callback use this logic: !elTextSecCurrent || entry.isIntersecting && elTextSecCurrent !== entry.target

Here's the final code with simplified CSS, HTML, and JS:

const $textSec = $(".text-sec"); // Cache your elements!
const $mainImg = $("#mainImage"); // Cache your elements!
let elTextSecCurrent; // to store the currently active textSec Element

function inViewportTextSec(entry) {
  if (!elTextSecCurrent || entry.isIntersecting && elTextSecCurrent !== entry.target) {
    // If the element is in the viewport, add the active class
    $textSec.removeClass("active");
    $(entry.target).addClass("active");
    $mainImg.attr("src", $(entry.target).data("src"));
    elTextSecCurrent = entry.target;
    console.log( /*TEST!*/ `Current video src: ${entry.target.dataset.src}`);
  }
}

const observer = new IntersectionObserver((entries) => {
  entries.forEach(inViewportTextSec);
}, {
  threshold: 0.4
});

$textSec.each(function() {
  observer.observe(this);
});
:root {
    --box-bg-color: #f0f0f0;
}

.text-sec {
    padding: 10px 20px;
    border-radius: 10px;
    margin: 50vh 0;
    translate: 0 -50%;

    &.active {
        border: none;
        background: var(--box-bg-color);
    }

    h3 {
        color: orange;
    }
}

.featured-img {
    position: sticky;
    top: 0px;
    width: 100%;
    height: 100vh;
    background: #000;

    video {
        display: block;
        width: 100%;
        height: 100%;
        object-fit: cover;
    }
}
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"
        crossorigin="anonymous">

<section id="videoonscroll" class="container">
  <div class="row side-text">
    <div class="col img-links">
      <div class="text-sec" data-src="video1.mp4">
        <h3>Better writing,<br>better results</h3>
        <p>Be perfectly professional, clear, and convincing in a few
          clicks, not a few hours.</p>
      </div>
      <div class="text-sec" data-src="video2.mp4">
        <h3>The right text<br>for the context</h3>
        <p>Get personalized suggestions based on what you"re writing
          and who will read it.</p>
      </div>
      <div class="text-sec" data-src="video3.mp4">
        <h3>Works where<br>you work</h3>
        <p>Grammarly works across all the apps and sites you use. No
          copying, no pasting, no context switching.</p>
      </div>
      <div class="text-sec" data-src="video4.mp4">
        <h3>Never go out of style</h3>
        <p>Grammarly understands both your personal style and your
          brand style guide to help you find your voice.</p>
      </div>
      <div class="text-sec" data-src="video5.mp4">
        <h3>This is responsible AI</h3>
        <p>Don"t compromise on security. We never sell your data,
          provide it for advertising purposes, or allow third parties to use it to train their
          models.</p>
      </div>
      <!-- Add more divs as needed -->
    </div>
    <div class="col">
      <div class="featured-img">
        <video id="mainImage" src="video1.mp4" poster="video1.png" autoplay loop muted playsinline></video>
      </div>
    </div>
  </div>
</section>

<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/js/bootstrap.min.js"></script>
like image 114
Roko C. Buljan Avatar answered Dec 08 '25 17:12

Roko C. Buljan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!