sGlow
sGlow

Reputation: 445

Javascript: How to change the images inside of a div on scroll?

so I am trying to create the effect seen on this website (for the photos on the left side of the column): https://www.franshalsmuseum.nl/en/

I want to be able to change the image on scroll inside of a div. And preferably, it won't scroll down past the page until all of the images have been scrolled through!

I'm trying to get the hang of javascript before adding things like jQuery, so can someone help with this using pureJS?`

window.onscroll = function() {
    console.log(window.pageYOffset);
    var img1 = document.getElementById('img1');
    var img2 = document.getElemebtById('img2')
    if ( window.pageYOffset > 1000 ) {
        img1.classList.add("hidden");
        img2.classList.remove("hidden");
    } else {
        img2.classList.add("hidden");
        img1.classList.remove("hidden");
    }
}
.rightPhotos {
    max-width: 50%;
    height: 50%;
    overflow: auto;
}

.aPhoto {
    max-height: 100%;
}

.hidden {
    visibility: hidden;
}

.images {
    width: 100%;
    height: 100%;
}
      <div class="other">
          <div class="rightPhotos" onscroll="myFunction()">
              <div class="aPhoto">
                  <img class ="images" id="img1" src="IMAGES/sunglasses.jpeg"  alt="Woman with Sunglasses">
              </div>
              <div class="aPhoto hidden">
                  <img class="images" src="IMAGES/dancer1.jpg" alt="A Dancer">
              </div>
          </div>
      </div>

`

Upvotes: 3

Views: 3055

Answers (4)

Frax
Frax

Reputation: 5865

The page you linked actually looks very nice, so I took a while to make something looking a bit closer to it than what other answers do.

  • I added a properly working transition, similar to one on franshalsmuseum.nl.
  • I styled the page to deal relatively well with being resized:
    • The sizing of panes and images is all ralative,
    • Scroll steps are relative to page height,
    • Images are shown using <div> with background-image instead of <img> tag. Depending on the size of the window, they are slightly cropped to adjust to changing aspect ratio of viewport.
  • I made the number of image sets very simple to change. It could be improved by creating the html elements in Javascript, but that doesn't look necessary. At least, it wouldn't be for the original page.

How it works

HTML

Images are put into special envelop elements (.img-wrapper), that provide proper sizing and positioning position: relative is important there). Each image element gets url (as background image url) and image set number to be used by javascript:

<div class="img visible" data-imageset="1"
    style="background-image: url('http://placeimg.com/640/480/people');">
</div>

Class visible is set to show imageset 1 at the beginning.

CSS

The key points are these definitions (and similar for #bottom-image). As the element enveloping the image has overflow: hidden, we can hide the image by moving it outside of visible area. When we set coordinates back to normal, the image will slide back, using the smooth transition.

/* hiding images in #top-image */
#left-pane #top-image .img {
  top: 100%;
}
#left-pane #top-image .img.visible {
  top: 0;
}

JS

The Javascript code is very minimal, the interaction with DOM is really one line. However, it uses some tricks that may not be obvious, so there is this line with some links to documentation:

document.querySelectorAll('#left-pane .img').forEach((img) => {
    img.classList.toggle('visible', img.dataset.imageset <= currentSet);
}

It just finds all images and adds or removes class visible depending on the data-imageset attribute of the image.

Full snippet with demo

See snippet below. Demo looks much better if you use "Full page" link after running the snippet.

let currentSet = 1;

function updateSelectedImgSet() {
  const currentScroll = document.scrollingElement.scrollTop;
  const scrollMax = document.scrollingElement.scrollHeight - document.scrollingElement.clientHeight;
  const setsCount = 3;
  const scrollPerSet = scrollMax / setsCount;
  const scrolledSet = Math.floor(currentScroll / scrollPerSet) + 1;
  if (scrolledSet == currentSet) {
    return;
  }
  currentSet = scrolledSet;
  document.querySelectorAll('#left-pane .img').forEach((img) => {
    img.classList.toggle('visible', img.dataset.imageset <= currentSet);
  });
}

window.onscroll = updateSelectedImgSet;
window.onresize = updateSelectedImgSet;
/* Left pane, fixed */
#left-pane {
  position: fixed;
  height: 100%;
  width: 40vw;
}

#left-pane .img-wrapper {
  position: relative;
  height: 50%;
  width: 100%;
  overflow: hidden;
}

#left-pane .img-wrapper .img {
  position: absolute;
  width: 100%;
  height: 100%;
  /* Sizing and cropping of image */
  background-position: center;
  background-size: cover;
  /* Transition - the slow sliding of images */
  transition: 0.5s all ease-in-out;
}

/* hiding images in #top-image */
#left-pane #top-image .img {
  top: 100%;
}
#left-pane #top-image .img.visible {
  top: 0;
}

/* hiding images in #bottom-image */
#left-pane #bottom-image .img {
  bottom: 100%;
}
#left-pane #bottom-image .img.visible {
  bottom: 0;
}

/* Right pane, scrolling with the page */

#right-pane {
  margin-left: 40vw;
}

.scrollable-content {
  font-size: 40vw;
  writing-mode: vertical-rl;
  white-space: nowrap;
}
<div id="left-pane">
  <div id="top-image" class="img-wrapper">
    <div class="img visible" data-imageset="1"
        style="background-image: url('http://placeimg.com/640/480/people');">
    </div>
    <div class="img" data-imageset="2"
        style="background-image: url('http://placeimg.com/640/480/animals');">
    </div>
    <div class="img" data-imageset="3"
        style="background-image: url('http://placeimg.com/640/480/any');">
    </div>
  </div>
  <div id="bottom-image" class="img-wrapper">
    <div class="img visible" data-imageset="1"
        style="background-image: url('http://placeimg.com/640/480/nature');">
    </div>
    <div class="img" data-imageset="2"
        style="background-image: url('http://placeimg.com/640/480/tech');">
    </div>
    <div class="img" data-imageset="3"
        style="background-image: url('http://placeimg.com/640/480/arch');">
    </div>
  </div>
</div>
<div id="right-pane">
  <div class="scrollable-content">Scrollable content!</div>
</div>

Upvotes: 2

BeeBee8
BeeBee8

Reputation: 3074

//window.pageYOffset

var scrollingDiv = document.getElementById('scrollContainer');
var img1 = document.getElementById('img1');
var img2 = document.getElementById('img2');

  scrollingDiv.onscroll = function(event) {

  if (scrollingDiv.scrollTop < 500) {
    img1.src = "https://placeimg.com/250/100/arch";
    img2.src = "https://placeimg.com/250/100/animals";
  }
  
  if (scrollingDiv.scrollTop > 500) {
    img1.src = "https://placeimg.com/250/100/nature";
    img2.src = "https://placeimg.com/250/100/people";
  }
  if (scrollingDiv.scrollTop > 1000) {
    img1.src = "https://placeimg.com/250/100/tech";
    img2.src = "https://placeimg.com/250/100/any";
  }
 
  
}
.container{
  display: table;
  width: 100%;
  height: 100%;
 }
 body{
 margin: 0;
 }
.container > div {
  vertical-align:top;
 }
 .left, .middle, .right {
   display: table-cell;
   height: 100vh;
   box-sizing: border-box;
   
 }
 .left, .right{
   width:40%;
   background: gray;
 }
 
 .middle{
   overflow: auto;
   position: relative;
 }
 
 .in-middle{
   background: tomato;
    position: absolute;
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    margin: 0;
 }
 .in-in-middle{
   height: 500px;
   background: tomato;
 }
 
 .in-in-middle:nth-child(2){
  background: pink;
 }
 
 .in-in-middle:nth-child(3){
  background: skyblue;
 }
 
 .left img{
  width: 100%;
  transition: all 0.5s;
 }
<div class="container">
  <div class="left">
    <img id="img1" src="https://placeimg.com/250/100/arch">
    <img id="img2" src="https://placeimg.com/250/100/animals">
  </div>
  <div class="middle" id="scrollContainer">
    <div class="in-middle">
      <div class="in-in-middle" id="1"></div>
      <div class="in-in-middle" id="2"></div>
      <div class="in-in-middle" id="3"></div>
    </div>
  </div>
</div>

Upvotes: 0

wonderlearner
wonderlearner

Reputation: 90

You can use the CSS properties to show/ hide the elements; instead of having custom CSS with hidden class.

if ( window.pageYOffset > 1000 ) {
        img1.style.visibility = 'hidden';  
        img2.style.visibility = 'visible';  
    } else {
        img2.style.visibility = 'hidden';  
        img1.style.visibility = 'visible';  
}

The above would hide the element, but the DOM element would still occupy space.

For it now to have space occupied (like to remove it)

if ( window.pageYOffset > 1000 ) {
        img1.style.display = 'none';
        img2.style.display = 'block';
    } else {
        img1.style.display = 'block';
        img2.style.display = 'none'; 
}

Upvotes: 0

לבני מלכה
לבני מלכה

Reputation: 16251

see code bellow:(I set 60 insteed 1000 (in function)for see changes)

I use one image and onscroll change the src of image

window.onscroll = function() {
    var img1 = document.getElementById('img1');
    var img2 = document.getElementById('img2')
    if ( window.pageYOffset > 60 ) {
 document.getElementById("img1").src = "https://material.angular.io/assets/img/examples/shiba2.jpg";
    } else {
 document.getElementById("img1").src = "https://material.angular.io/assets/img/examples/shiba1.jpg";
    }
}
.rightPhotos
{
    max-width: 50%;
    height:50%;

    overflow: auto;
}
.aPhoto
{

    max-height: 100%;


}



.images
{
    width: 100%;
    height: 500px;
}
      <div class="other">
         <div class="rightPhotos" onscroll="myFunction()">
           <div class="aPhoto">
               <img class ="images" id="img1" src="https://material.angular.io/assets/img/examples/shiba1.jpg"  alt="Woman with Sunglasses"/>
   </div>

  </div>

 </div>

Upvotes: 0

Related Questions