Search code examples
javascriptforeachaddeventlistenerappendchild

How to make image title display on scroll


I am trying to make sure javascript displays the image title for every image on the screen. I seem to have found out how to convert the title as text node but I have no idea how to make sure the text only shows when the image is on-screen and goes away when the image goes off-screen.

Plain javascript only please. Thank you.

ri.addEventListener("scroll", function iT() {
  const iA = Array.from(document.querySelectorAll("#right img"));
  aP = document.querySelector(".aboutProject");

  iA.forEach(function(item) {
    const iT = item.title;
    const iP = item.getBoundingClientRect().top;

    const wH = window.innerHeight / 1.2;
    if (iP < wH && iP >= 0) {
      const h = document.createElement("H4");
      const t = document.createTextNode(iT);
      h.appendChild(t);
      aP.appendChild(h);
    }
  });
});
* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
  -moz-box-sizing: border-box;
  -webkit-box-sizing: border-box;
}

body {
  background-color: rgb(254, 238, 228);
  max-width: 100vw;
  min-height: auto;
}

.container {
  display: grid;
  grid-template-columns: 1fr 1fr;
}

.aboutProject {
  display: grid;
  align-content: center;
  justify-items: center;
}

#right {
  width: 50vw;
  height: 100vh;
  display: grid;
  align-items: center;
  justify-content: center;
  overflow-x: hidden;
  overflow-y: auto;
}

#right a img {
  height: 92.5vh;
  width: 50vw;
  object-fit: cover;
  object-position: center;
}
<div class="container">
  <div class="aboutProject">
    <h4>title comes here</h4>
  </div>

  <div id="right">
    <a href="project6" id="lastClone"><img src="https://www.metoffice.gov.uk/binaries/content/gallery/metofficegovuk/hero-images/weather/cloud/cumulus-cloud.jpg" title="project 6clone" /></a>
    <a href="project1"><img src="https://cdn1.epicgames.com/ue/product/Screenshot/StoreUltraDynamicSkyscreenshot1-1920x1080-f5d2cdb93df61507a2e584354de459ca-1920x1080-a431ce7a2eb0a4eb720b25de2ba0aca3.png" title="project 1" /></a>
    <a href="project2"><img src="https://www.rolls-roycemotorcars.com/content/dam/rrmc/marketUK/rollsroycemotorcars_com/2-6-4-under-the-stars/page-properties/rolls-royce-under-the-stars-hero-d.jpg" title="project 2" /></a>
    <a href="project3"><img src="https://www.citynews1130.com/wp-content/blogs.dir/sites/9/2018/05/27/iStock-697020460.jpg" title="project 3" /></a>
    <a href="project4"><img src="https://lh6.googleusercontent.com/GlbCESxjIY2pjzV9B9hwoySVG6sJRErg_ylUlHt2XUm2PWhDpDWBZMOkUL0s4wMImdG8LP8Xm6KfB3KPVddCiBGSJO9psgZ13DkPSjNUngDg1iyGkQvxOQXdLDp1PXyF9b-lVSQ" title="project 4" /></a>
    <a href="project5"><img src="https://www.esa.int/var/esa/storage/images/esa_multimedia/images/2019/07/moon_seen_from_space_station/19494773-1-eng-GB/Moon_seen_from_Space_Station_pillars.jpg" title="project 5" /></a>
    <a href="project6"><img src="https://www.metoffice.gov.uk/binaries/content/gallery/metofficegovuk/hero-images/weather/cloud/cumulus-cloud.jpg" title="project 6" /></a>
    <a href="project1" id="firstClone"><img src="https://cdn1.epicgames.com/ue/product/Screenshot/StoreUltraDynamicSkyscreenshot1-1920x1080-f5d2cdb93df61507a2e584354de459ca-1920x1080-a431ce7a2eb0a4eb720b25de2ba0aca3.png" title="project 1clone" /></a>
  </div>
</div>


Solution

  • You'll want to use the IntersectionObserver API. This API is used to see if elements enter or exit the viewport of the user, like when the user scrolls or swipes. And it does this fast and without having to make complex calculations.

    An instance of an IntersectionObserver takes a callback function and an options object. Inside the callback of the observer you can check if an entry (which is the element you are observing and more) is intersecting or not, meaning if it is in view or not in the view. The options are to determine when to trigger the callback.

    Great to hear that you figured out how to append elements to the document based on an attribute the img element. But in this case, I assume, your title will always be the same so there is no need to dynamically generate the title of the image. Simply add the title in the HTML and hide it with CSS. Then when the image comes into view show the title by adding a class.
    Whenever an image leaves the viewport remove the class and CSS.

    I've modified your example below to demonstrate the IntersectionObserver.

    // Callback that is fired whenever an entry enters or leaves the view.
    function intersectionCallback(entries) {
      entries.forEach(entry => {
        const { target, isIntersecting } = entry;
        if (isIntersecting && !target.classList.contains('show')) {
          target.classList.add('show');
        } else {
          target.classList.remove('show');
        }
      });
    }
    
    // Options for the observer.
    const observerOptions = {
      rootMargin: '50px 0px'
    };
    
    // Create an instance of the observer with the callback and the options.
    const observer = new IntersectionObserver(intersectionCallback, observerOptions);
    
    // Select the right images and observe them all.
    const rightImages = document.querySelectorAll("#right a");
    rightImages.forEach(image => observer.observe(image));
    * {
      padding: 0;
      margin: 0;
      box-sizing: border-box;
      -moz-box-sizing: border-box;
      -webkit-box-sizing: border-box;
    }
    
    body {
      background-color: rgb(254, 238, 228);
      max-width: 100vw;
      min-height: auto;
    }
    
    #right {
      width: 50vw;
      height: 100vh;
      display: grid;
      align-items: center;
      justify-content: center;
      overflow-x: hidden;
      overflow-y: auto;
    }
    
    #right a {
      display: grid;
      align-items: center;
      justify-content: center;
      text-decoration: none;
    }
    
    #right a img {
      grid-area: 1 / 1 / 2 / 2;
      height: 92.5vh;
      width: 50vw;
      object-fit: cover;
      object-position: center;
    }
    
    #right a h4 {
      grid-area: 1 / 1 / 2 / 2;
      color: white;
      text-transform: uppercase;
      opacity: 0;
      text-align: center;
      transition: opacity 250ms 250ms ease-in-out;
      z-index: 1;
    }
    
    #right a.show h4 {
      opacity: 1;
    }
    <div class="aboutProject"></div>
    
    <div id="right">
      <a href="project6" id="lastClone">
        <img src="https://www.metoffice.gov.uk/binaries/content/gallery/metofficegovuk/hero-images/weather/cloud/cumulus-cloud.jpg" title="project 6clone" />
        <h4>project 6clone</h4>
      </a>
      <a href="project1"><img src="https://cdn1.epicgames.com/ue/product/Screenshot/StoreUltraDynamicSkyscreenshot1-1920x1080-f5d2cdb93df61507a2e584354de459ca-1920x1080-a431ce7a2eb0a4eb720b25de2ba0aca3.png" title="project 1" />
        <h4>project 1</h4>
      </a>
      <a href="project2"><img src="https://www.rolls-roycemotorcars.com/content/dam/rrmc/marketUK/rollsroycemotorcars_com/2-6-4-under-the-stars/page-properties/rolls-royce-under-the-stars-hero-d.jpg" title="project 2" />
        <h4>project 2</h4>
      </a>
      <a href="project3"><img src="https://www.citynews1130.com/wp-content/blogs.dir/sites/9/2018/05/27/iStock-697020460.jpg" title="project 3" />
        <h4>project 3</h4>
      </a>
      <a href="project4"><img src="https://lh6.googleusercontent.com/GlbCESxjIY2pjzV9B9hwoySVG6sJRErg_ylUlHt2XUm2PWhDpDWBZMOkUL0s4wMImdG8LP8Xm6KfB3KPVddCiBGSJO9psgZ13DkPSjNUngDg1iyGkQvxOQXdLDp1PXyF9b-lVSQ" title="project 4" />
        <h4>project 4</h4>
      </a>
      <a href="project5"><img src="https://www.esa.int/var/esa/storage/images/esa_multimedia/images/2019/07/moon_seen_from_space_station/19494773-1-eng-GB/Moon_seen_from_Space_Station_pillars.jpg" title="project 5" />
        <h4>project 5</h4>
      </a>
      <a href="project6"><img src="https://www.metoffice.gov.uk/binaries/content/gallery/metofficegovuk/hero-images/weather/cloud/cumulus-cloud.jpg" title="project 6" />
        <h4>project 6</h4>
      </a>
      <a href="project1" id="firstClone"><img src="https://cdn1.epicgames.com/ue/product/Screenshot/StoreUltraDynamicSkyscreenshot1-1920x1080-f5d2cdb93df61507a2e584354de459ca-1920x1080-a431ce7a2eb0a4eb720b25de2ba0aca3.png" title="project 1clone" />
        <h4>project 1clone</h4>
      </a>
    </div>

    If you have any questions, or I've been unclear, please let me know.