javascripthtmlcss3dparallax

How can I create a 3D illusion by moving the background image layer when scrolling (Parallax effect)?


I have stacked two images on top of each other in the heading. As the user scrolls, I aim to create a subtle vertical movement in the background image to achieve a 3D illusion. Both images have the same width, but the background image is taller.

Here's the website: https://johanstemplate.w3spaces.com/

After searching on Google, I found implementations using both CSS and JavaScript to achieve this effect, and it seems to be called the Parallax effect.

The bottom of the background image should align with the bottom of the front image when the page is at the top. As the user scrolls further down and the header image disappears from view, I'd like the top of the background image to align with the top of the front image. Would this be the right direction to achieve the 3D-illusion?

The design is responsive and it would be awesome if the effect works on both phones and desktops. However, desktop compatibility is most important. Using javascript would be ok if CSS is impossible or to complicated.

body {
  background: gray;
  font-size: 140%
}

.content {
  margin: 50px auto 0px auto;
  max-width: 1100px;
  padding-bottom: 2000px;
  padding-top: 30px;
  background-color: white;
  border: solid black;
  border-width: 0px 16px 0px 16px;
}

.margin-content {
  margin: 30px 80px 0px 100px;
}

.header-img {
  width: 100%;
  background-image: url("https://i.sstatic.net/r6CD4.jpg");
  background-size: contain;
}
<div class="content">
  <div class="margin-content">
    <h1> My Brand </h1>
  </div>
  <img src="https://i.sstatic.net/uxvh2.png" class="header-img" />
  <div class="margin-content">
    <h2>Lorem ipsum dolor sit amet..</h2>
    <p>..consectetur adipiscing elit. Fusce ex erat, vehicula vitae sapien vel, dignissim ornare odio.</p>
  </div>
</div>
</div>
<p style="color:white;text-align: center; position: relative; top:13px">© 2048 My Brand</p>

Any help would be highly appreciated! :)


Solution

  • There are two ways you could go about doing this.

    First of all is to just simply set background-attachment: fixed; so that the background image is not affected when you scroll. Note that I also added the following CSS

    background-size: cover;
    background-repeat: no-repeat;
    background-position: center;
    

    body {
      background: gray;
      font-size: 140%
    }
    
    .content {
      margin: 50px auto 0px auto;
      max-width: 1100px;
      padding-bottom: 2000px;
      padding-top: 30px;
      background-color: white;
      border: solid black;
      border-width: 0px 16px 0px 16px;
    }
    
    .margin-content {
      margin: 30px 80px 0px 100px;
    }
    
    .header-img {
      width: 100%;
      background-image: url("https://i.sstatic.net/r6CD4.jpg");
      background-size: cover;
      background-repeat: no-repeat;
      background-position: center;
      background-attachment: fixed;
    }
    <div class="content">
      <div class="margin-content">
        <h1> My Brand </h1>
      </div>
      <img src="https://i.sstatic.net/uxvh2.png" class="header-img" />
      <div class="margin-content">
        <h2>Lorem ipsum dolor sit amet..</h2>
        <p>..consectetur adipiscing elit. Fusce ex erat, vehicula vitae sapien vel, dignissim ornare odio.</p>
      </div>
    </div>
    <!--</div>-->
    <p style="color:white;text-align: center; position: relative; top:13px">© 2048 My Brand</p>

    The second is to use some javascript. I took this from a project where I used parallax effect on background images just like you are asking. It's a bit more subtle here since the image is so large. Note that I also added/changed the following CSS

    background-size: 150%;
    background-repeat: no-repeat;
    background-position: center;
    

    If background-size: cover or background-size: contain was used here it wouldn't really scroll properly since since it would have nowhere to go, so it just has to be sized up a bit to be larger than the container

    const parallaxBgImg = document.querySelector('#parallax-bg-img');
    
    document.addEventListener('scroll', (event)=>{
      const rect = parallaxBgImg.getBoundingClientRect();
    
      if (rect.top < window.innerHeight) {
        const scrollableDistance = window.innerHeight + rect.height;
        const scrolled = window.innerHeight - rect.top;
        const percent = (scrolled / scrollableDistance) * 100;
        //don't go over 100% - can happen with elastic scroll on touch devices
        const finalPercent = Math.min(percent, 100);
        
        //Uncomment and use this instead for the opposite direction
        //parallaxBgImg.style.backgroundPositionY = `${finalPercent}%`;
        
        //Reversed direction
        const invertedPct = 100 - finalPercent;
        parallaxBgImg.style.backgroundPositionY = `${invertedPct}%`;
      }
    });
    body {
      background: gray;
      font-size: 140%
    }
    
    .content {
      margin: 50px auto 0px auto;
      max-width: 1100px;
      padding-bottom: 2000px;
      padding-top: 30px;
      background-color: white;
      border: solid black;
      border-width: 0px 16px 0px 16px;
    }
    
    .margin-content {
      margin: 30px 80px 0px 100px;
    }
    
    .header-img {
      width: 100%;
      background-image: url("https://i.sstatic.net/r6CD4.jpg");
      background-size: 150%;
      background-repeat: no-repeat;
      background-position: center;
    }
    <div class="content">
      <div class="margin-content">
        <h1> My Brand </h1>
      </div>
      <img src="https://i.sstatic.net/uxvh2.png" class="header-img" id="parallax-bg-img" />
      <div class="margin-content">
        <h2>Lorem ipsum dolor sit amet..</h2>
        <p>..consectetur adipiscing elit. Fusce ex erat, vehicula vitae sapien vel, dignissim ornare odio.</p>
      </div>
    </div>
    <!--</div>-->
    <p style="color:white;text-align: center; position: relative; top:13px">© 2048 My Brand</p>