skip to Main Content

I have 4 cards that contain images. When the image is in viewport I want the image to come from the left. I have finished all the css but when I run the JS, it always returns false even if the element is in viewport. I don’t need the whole image to be in the viewport at least half of it and I want it to return true. I have a for each loop that runs through all of the images but it always returns false.

This is the code that I have come up with:

function isInViewport(container) {
  const rect = container.getBoundingClientRect();
  
  return (
    rect.top >= 0 &&
    rect.left >= 0 &&
    rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
    rect.right <= (window.innerWidth || document.documentElement.clientWidth)
  );
}

this is the html:

      <div class="col-md-6 col-sm-12 p-0 overflow-hidden bg-dark imageCard">
        <div class="imageCont">
          <img
            src="images/ferrariPhoto1.webp"
            alt=""
            style="width: 100%; height: 100%"
            class="ferrariImageSection"
          />
        </div>
      </div>

2

Answers


  1. I made a simple example using your function in codepen, and it looks like your function is working as expected: https://codepen.io/lukenetsurfer/pen/WNPzQdO

    The example includes a blue square that you can drag around the screen. If you open the console, you can see it print out the result of isInViewport each time you move the square. When the square is only partially visible (it’s hanging off the screen), isInViewport returns false, otherwise it returns true.

    A few debugging ideas to help you figure out why it’s not working on your end:

    • If you console.log container, does it have the value you expect? (Maybe you’re checking the wrong component?)
    • If you console.log the values in your boolean comparison, do those match your expectations?
    Login or Signup to reply.
  2. Use Intersection Observer as Darryl Noakes commented earlier.

    I can’t really help you with specifics because the code posted in the question seems incomplete and the explanation is missing some critical details. The example below uses IO and details are in the comments.

    const options = {
      root: null, // Defaults to null which is <html> / viewport
      rootMargin: "0px", // Defaults to 0 - values are 1 to 4 numbers in px. 
      threshold: [0.25, 0.75]
      /* a single or array of numbers that
       represent the percentage of the target element length that's 
       visible. */
    };
    
    /** Create an Observer
     * Pass in the callback function and the options object.
     */
    const observer = new IntersectionObserver(showHideTitle, options);
    
    // Reference all of the elements .card
    const cards = document.querySelectorAll(".card");
    
    // Target each .card with the observer
    cards.forEach(card => observer.observe(card));
    
    /** Callback Function
     * Whenever a .card is within either thresholds (0.25 or 0.75), 
     * this callback function fires.
     * Entries is a list of entry objects.
     * Each entry object has several properties associated 
     * with a specific target element (.card).
     * The property .target will return the element that triggered
     * the observer.
     * The property .intersectionRatio returns a number that
     * represents the percentage of the target element that
     * is within the viewport.
     */
    function showHideTitle(entries, observer) {
      entries.forEach((entry) => {
        let text = entry.target.firstElementChild;
        if (entry.intersectionRatio > 0.75) {
          text.classList.add("fade-in");
          text.classList.remove("fade-out");
        } else {
          text.classList.remove("fade-in");
          text.classList.add("fade-out");
        }
      });
    }
    * {
      margin: 0;
      padding: 0;
    }
    
    :root {
      font: 5vmin/1 "Segoe UI";
    }
    
    body {
      display: flex;
      flex-wrap: nowrap;
      align-items: center;
      width: max-content;
      height: 100vh;
      overflow-x: scroll;
      overflow-y: hidden;
      background: #F6F3F5;
    }
    
    #list {
      display: flex;
      flex-wrap: nowrap;
      justify-content: center;
      align-items: center;
      width: max-content;
      overflow: hidden;
    }
    
    .card {
      display: block;
      min-width: 100vw;
      color: transparent;
    }
    
    .directions {
      display: flex;
      justify-content: center;
      align-items: center;
      min-height: 100%;
    }
    
    p {
      font-size: 1.5rem;
    }
    
    figure {
      width: 100%;
    }
    
    figcaption {
      width: 100%;
      text-align: center;
      font-size: 2rem;
    }
    
    img {
      display: block;
      width: 100%;
      height: auto;
      transform: rotateY(180deg);
    }
    
    .text {
      position: relative;
      z-index: 1;
    }
    
    .fade-in {
      color: black;
      transition: 1s;
    }
    
    .fade-out {
      color: transparent;
      transition: 1s;
    }
    <ol id="list">
      <li class="card directions">
        <p class="text">Scroll to the right. &gt;</p>
      </li>
      <li class="card">
        <figure>
          <figcaption class="text">Lamborghini</figcaption>
          <img src="https://i.ibb.co/g3MmqLY/car1.png">
        </figure>
      </li>
      <li class="card">
        <figure>
          <figcaption>Lotus</figcaption>
          <img src="https://i.ibb.co/7Cqhsy7/car2.png">
        </figure>
      </li>
      <li class="card">
        <figure>
          <figcaption class="text">Alpha Romeo</figcaption>
          <img src="https://i.ibb.co/8z6JZ56/car3.png">
        </figure>
      </li>
      <li class="card">
        <figure>
          <figcaption class="text">Farrai</figcaption>
          <img src="https://i.ibb.co/KsFfVBk/car4.png">
        </figure>
      </li>
      <li class="card directions">
        <p class="text">&lt; Scroll to the left.</p>
      </li>
    </ol>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search