Полноэкранный фон с бесконечной прокруткой

Я пытаюсь реализовать полноэкранный фоновый эффект бесконечной прокрутки, который должен распространяться на всю высоту и ширину области просмотра.

Вот демонстрация.

Решение, которое я пробовал, заключалось в том, чтобы взять элемент-оболочку, который имеет 100vh и 100vw области просмотра, а затем поместить внутри него 2 div, 100% его высоты, которые имеют такое же фоновое изображение и свойство background-size: cover. Размер изображения, которое я использовал, составляет: 1920 пикселей × 808 пикселей.

Затем я применил следующую анимацию к элементу-оболочке:

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

Но проблема в том, что при некоторых размерах области просмотра изображения повторяются неправильно (из-за свойства background-size: cover):

введите здесь описание изображения.

Вот полный код, который я пробовал:

<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>

И 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');
}

Есть ли у вас какие-либо идеи о том, как я могу реализовать этот эффект?

Спасибо за вашу помощь.


person andreivictor    schedule 02.05.2017    source источник


Ответы (5)


Я использовал элемент изображения только для того, чтобы использовать его автоматическую высоту.

Затем я использую бэкграунд на псевдо, который дает возможность повторяться столько раз, сколько нужно.

Я установил 2 разных контейнера с разным соотношением сторон, чтобы легче было проверить результат на разных экранах.

.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.stack.imgur.com/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.stack.imgur.com/FlK9o.jpg">
    </div>
</div>
<div class="container" id="ctn2">
    <div class="inner">
        <img class="img" src="https://i.stack.imgur.com/FlK9o.jpg">
    </div>
</div>

Лучшее решение с медиа-запросом, используемым для изменения способа использования изображения.

Обратите внимание, что background-size: cover требуется, когда соотношение сторон изображения и окна неизвестно. Поскольку вы знаете соотношение сторон вашего изображения, вы можете управлять отображением с помощью медиа-запроса на его основе.

Теперь при необходимости изображение будет подстраиваться не под ширину контейнера, а под его высоту

@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.stack.imgur.com/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.stack.imgur.com/FlK9o.jpg">
    </div>
</div>
<div class="container" id="ctn2">
    <div class="inner">
        <img class="img" src="https://i.stack.imgur.com/FlK9o.jpg">
    </div>
</div>

person vals    schedule 06.05.2017
comment
Отличная идея! Я реализовал его в своем примере, и он работает: codepen.io/andreivictor/pen/xdPwXr. - person andreivictor; 06.05.2017
comment
Играя с вашим codepen, я заметил, что в крайнем портретном соотношении нижняя часть экрана не закрыта. Вы должны изменить высоту псевдоэлемента на более чем 500% (скажем, 1000%), и тогда размер фона будет 100% 10% - person vals; 06.05.2017
comment
Да, я видел этот недостаток: imgur.com/a/PfKCU. Кроме того, высота 1000% сделает элемент слишком большим, и, возможно, анимация будет немного прерывистой. Я думаю, что полным решением было бы использование нескольких разных изображений в зависимости от размера экрана (для мобильных устройств, для планшетов и небольших настольных компьютеров, другое для экранов Full HD). Тем не менее, это лучший ответ, и я отмечу его как принятый. - person andreivictor; 06.05.2017
comment
Рад, что помогло! Но я не думаю, что такая высота делает анимацию прерывистой. Вы также можете переключиться на ширину: 50% (или меньше) в медиа-запросе. - person vals; 06.05.2017
comment
Я добавил лучшее решение. Надеюсь, вам понравится! - person vals; 07.05.2017

Проблема с соотношением сторон. Вы устанавливаете соотношение сторон окна просмотра, а не размер изображения. Таким образом, ваше изображение обрезается со стороны окна просмотра.

Я работал в вашем коде, изменив .animated-scene__frame на это:

 .animated-scene__frame {
    width: 100%;
    height:200vh; //easy way - increase height in animated div to prevent image cutoff. Ideally should be done through javascript using like a 3x multiple of the height of the image. Then just rely on background-repeat during the animation :)
    background-size:contain;
    background-color: #4277a3;
    background-image: url('https://andreivictor.ro/codepen/fullscreen-infinite-scroll-bg/fullscreen-bg-slide1.jpg');
 }
person Maarten    schedule 04.05.2017

Для прокрутки фона я использовал фоновую позицию вместо дополнительного элемента и анимировал его с помощью свойств преобразования css.

Почему вы можете спросить?

  1. Шаблон будет легко сшиваться браузерами
  2. более чистый HTML-код. Для этого нам нужен всего один элемент.

Единственная константа, использующая этот метод, - вам нужно знать размер изображения, которое вы используете.

Пример :

/*
  specify the scroll x (or y) with the width (or height) of the images
  In this case, the image dimension is :
  width: 1920px;
  height: 808px;
*/

@keyframes bgScroll {
  0% {
    background-position : 0px 0px
  }
  100% {
    background-position : 0px -808px
  }
}

.scrollingBG {
  display:block;
  width:100vw;
  height:100vh;
  background-image:url("https://andreivictor.ro/codepen/fullscreen-infinite-scroll-bg/fullscreen-bg.jpg");
  animation: bgScroll 20s linear infinite;
}
<div class='scrollingBG'></div>

person Donovan P    schedule 13.08.2020
comment
Спасибо, ваше решение идеально подходит к задаче. - person andreivictor; 13.08.2020
comment
Анимация background-position не очень эффективна, так как вызывает много перерисовок. Вместо этого лучше использовать переводы. - person Brendon Muir; 10.05.2021

Я бы рекомендовал просто расширить изображение 3 раза, с:

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

Воспользуйтесь графическим редактором и создайте большое изображение с тем же шаблоном. Взгляните на этот сайт, который я сделал на сайте. , там вы найдете какой-то бесконечный фоновый узор

person Felipe Valencia    schedule 02.05.2017
comment
В вашем примере движущийся элемент имеет фиксированные размеры: высота - 396 пикселей и ширина - 5758 пикселей.... Я пытаюсь создать что-то, что занимает 100% размера экрана и идеально на нем помещается. - person andreivictor; 04.05.2017

Вы должны использовать свойство background-position. Вот фиксированный пример: http://codepen.io/azamat7g/pen/BRwRVV

Полный код:

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

.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-position: bottom left;
  background-color: #4277a3;
  background-image: url('https://andreivictor.ro/codepen/fullscreen-infinite-scroll-bg/fullscreen-bg-slide1.jpg');
}

.bottom{
  background-position: top left;
}
<div class="animated-scene">
  <div class="animated-scene__frame animated-scene__frame-1"></div>
  <div class="animated-scene__frame animated-scene__frame-2 bottom"></div>
</div>

person Azamat Mirvosiqov    schedule 05.05.2017
comment
Это не зацикливается... в конце анимации изображение прыгает из-за другого положения фона. - person andreivictor; 05.05.2017