Search code examples
csscss-animationstranslate-animationbackground-size

Fullscreen infinite scrolling background


I'm trying to implement a full-screen infinite scrolling background effect, which must extend on the entire height and width of the viewport.

Here's the demo.

The solution I've tried was to take a wrapper element that has 100vh and 100vw of the viewport, then place 2 divs inside it, 100% of its height, that have the same background-image and background-size: cover property. The size of the image I've used is: 1,920px × 808px.

Then I've applied the following animation on the wrapper element:

@keyframes infiniteScrollBg {
  0% {
    transform: translateY(0%);
  }
  100%{
    transform: translateY(-100%);
  }
}

But the problem is that on some viewport sizes, the images are not repeating correctly (because of background-size: cover property):

enter image description here.

Here's the full code I've tried:

<div class="animated-scene">
    <div class="animated-scene__frame animated-scene__frame-1"></div>
    <div class="animated-scene__frame animated-scene__frame-2"></div>
</div>

And the css:

.animated-scene {
    width: 100vw;
    height: 100vh;
    position: fixed;
    min-height: 400px;
    animation: infiniteScrollBg 50s linear infinite;
 }

 .animated-scene__frame {
     width: 100%;
     height: 100%;
     background-size: cover;
     background-color: #4277a3;
     background-image: url('https://andreivictor.ro/codepen/fullscreen-infinite-scroll-bg/fullscreen-bg');
}

Do you have any idea on how could I implement this effect?

Thanks for your help.


Solution

  • I have used an image element just to use the auto height of it.

    Then I use a backgroiund on a pseudo that gives the ability to repeat itself as many times as needed

    I have set 2 different containers with different aspect ratios to more easily check the result on different screens

    .container {
      border: solid 1px black;
      overflow: hidden;
      position: absolute;
    }
    
    #ctn1 {
      width: 300px;
      height: 150px;
    }
    
    #ctn2 {
      width: 200px;
      height: 350px;
      left: 320px;
    }
    
    .inner {
      width: 100%;
      position: relative;
      animation: scroll 5s infinite linear;
    }
    
    .inner:after {
      content: "";
      height: 500%;
      width: 100%;
      position: absolute;
    
      background-image: url(https://i.sstatic.net/FlK9o.jpg);
      background-size: 100% 20%;
    }
    
    .img {
      width: 100%;
    }
    
    
    @keyframes scroll {
      from {transform: translateY(-100%);}
        to {transform: translateY(-200%);}
    
    }
    <div class="container" id="ctn1">
        <div class="inner">
            <img class="img" src="https://i.sstatic.net/FlK9o.jpg">
        </div>
    </div>
    <div class="container" id="ctn2">
        <div class="inner">
            <img class="img" src="https://i.sstatic.net/FlK9o.jpg">
        </div>
    </div>

    A better solution with media query used to change the way the image is used.

    Notice that background-size: cover is needed when both the aspect ratio of the image and the window is unknown. Since you know the aspect ratio of your image, you can control the display with a media query based on it.

    Now, when it's needed, the image will adapt not to the width of the container, but to the height of it

    @media screen and (max-aspect-ratio: 4/3) {
        .inner {
            height: 100%;
            width: auto !important;
        }
        .img {
           height: 100%;
           width: auto !important;
        }
    }
    
    
    .container {
      border: solid 1px black;
      display: inline-block;
      overflow: hidden;
    }
    
    #ctn1 {
      width: 300px;
      height: 150px;
    }
    
    #ctn2 {
      width: 200px;
      height: 350px;
    }
    
    .inner {
      width: 100%;
      position: relative;
      animation: scroll 5s infinite linear;
      display: inline-block;
    }
    
    
    .inner:after {
      content: "";
      height: 500%;
      width: 100%;
      left: 0px;
      position: absolute;
      background-image: url(https://i.sstatic.net/FlK9o.jpg);
      background-size: 100% 20%;
    }
    
    .img {
      width: 100%;
    }
    
    
    @keyframes scroll {
      from {transform: translateY(-100%);}
        to {transform: translateY(-200%);}
    
    }
    <div class="container" id="ctn1">
        <div class="inner">
            <img class="img" src="https://i.sstatic.net/FlK9o.jpg">
        </div>
    </div>
    <div class="container" id="ctn2">
        <div class="inner">
            <img class="img" src="https://i.sstatic.net/FlK9o.jpg">
        </div>
    </div>