Как анимировать background-position используя проценты, когда background-size равен 100%?

Возьмите следующий пример:

html {
    height: 100%;
}

body {
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: black;
    height: 100%;
    margin: 0;
}

#main {
    background: #222222;
    position: relative;
    flex: 640px 0 0;
    height: 360px;
}

@keyframes stars {
 0% {
        background-position: 0 0;
    }
 100% {
        background-position: -100% 0;
    }
}

#stars {
    animation: stars 10s linear infinite;
    background-image: url('https://i.imgur.com/nyFndCj.png');
    background-size: 100% 100%;
    background-repeat: repeat repeat;
    position: absolute;
    width: 100%;
    height: 100%;
}
<div id="main">
  <div id="stars"></div>
</div>

Идея здесь состоит в том, чтобы анимировать звезды, движущиеся от одной стороны к другой, изменяя положение фона с использованием процентов. Я могу заставить это работать, используя px Например, но это требует от меня знать ширину заранее (в этом случае 640px) и если я хочу изменить ширину / высоту #main Мне нужно изменить значения анимации, и я хочу избежать этого, таким образом, проценты. Кроме того, я хочу сделать это только с помощью CSS, без JavaScript вообще.

1 ответ

Решение

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

body {
  background-color: black;
  height: 100vh;
  margin: 0;
}

#main {
  background: #222222;
  position: relative;
  width: 100%;
  height: 360px;
  overflow: hidden;
}

#stars {
  animation: stars 10s linear infinite;
  background-image: url('https://i.imgur.com/nyFndCj.png');
  background-size: 50% 100%;
  position: absolute;
  left: 0;
  right: 0;
  height: 100%;
  transform: scaleX(2);
}

@keyframes stars {
  0% {
    background-position: left;
  }
  100% {
    background-position: right;
  }
}
<div id="main">
  <div id="stars"></div>
</div>

Вот еще одна идея без масштаба, где вы также увеличиваете элемент в два раза, используя right:-100% или же left:-100% или же width:200%

body {
  background-color: black;
  height: 100vh;
  margin: 0;
}

#main {
  background: #222222;
  position: relative;
  width: 100%;
  height: 360px;
  overflow: hidden;
}

#stars {
  animation: stars 10s linear infinite;
  background-image: url('https://i.imgur.com/nyFndCj.png');
  background-size: 50% 100%;
  position: absolute;
  left: 0;
  right: -100%;
  height: 100%;
}

@keyframes stars {
  0% {
    background-position: left;
  }
  100% {
    background-position: right;
  }
}
<div id="main">
  <div id="stars"></div>
</div>

Вот еще одно упрощение с учетом псевдоэлемента:

body {
  background-color: black;
  height: 100vh;
  margin: 0;
}

#main {
  position: relative;
  width: 100%;
  height: 360px;
  overflow: hidden;
  z-index:0;
}
#main:before {
  content:"";
  position:absolute;
  z-index:-1;
  top:0;
  left:0;
  right:-100%;
  bottom:0;
  animation: stars 10s linear infinite;
  background: 
    url('https://i.imgur.com/nyFndCj.png') left/50% 100%,
    #222222;
}

@keyframes stars {
  100% {
    background-position: right;
  }
}
<div id="main">
</div>

В любом случае, хитрость заключается в том, чтобы избежать 100% 100% в background-size или это будет невозможно анимировать с использованием процентов.


я использовал left / right для упрощения, которое эквивалентно 0% 50% / 100% 50%, Просто переключайтесь между ними, чтобы изменить направление.

Более подробная информация здесь: /questions/28327775/ispolzovanie-protsentnyih-znachenij-s-background-position-na-linejnom-gradiente/28327778#28327778


И так как мы увеличили размер контейнера, мы также можем анимировать его, используя translate, чтобы повысить производительность:

body {
  background-color: black;
  height: 100vh;
  margin: 0;
}

#main {
  position: relative;
  width: 100%;
  height: 360px;
  overflow: hidden;
  z-index:0;
}
#main:before {
  content:"";
  position:absolute;
  z-index:-1;
  top:0;
  left:0;
  right:-100%;
  bottom:0;
  animation: stars 10s linear infinite;
  background: 
    url('https://i.imgur.com/nyFndCj.png') left/50% 100%,
    #222222;
}

@keyframes stars {
  100% {
    transform: translateX(-50%);
  }
}
<div id="main">
</div>

С масштабированием:

body {
  background-color: black;
  height: 100vh;
  margin: 0;
}

#main {
  position: relative;
  width: 100%;
  height: 360px;
  overflow: hidden;
  z-index:0;
}
#main:before {
  content:"";
  position:absolute;
  z-index:-1;
  top:0;
  left:0;
  right:0;
  bottom:0;
  transform:scaleX(2);
  transform-origin:left;
  animation: stars 10s linear infinite;
  background: 
    url('https://i.imgur.com/nyFndCj.png') left/50% 100%,
    #222222;
}

@keyframes stars {
  100% {
    transform:scaleX(2) translateX(-50%);
  }
}
<div id="main">
</div>

В другом направлении

body {
  background-color: black;
  height: 100vh;
  margin: 0;
}

#main {
  position: relative;
  width: 100%;
  height: 360px;
  overflow: hidden;
  z-index:0;
}
#main:before {
  content:"";
  position:absolute;
  z-index:-1;
  top:0;
  left:0;
  right:0;
  bottom:0;
  transform:scaleX(2);
  transform-origin:right;
  animation: stars 10s linear infinite;
  background: 
    url('https://i.imgur.com/nyFndCj.png') left/50% 100%,
    #222222;
}

@keyframes stars {
  100% {
    transform:scaleX(2) translateX(50%);
  }
}
<div id="main">
</div>

Другие вопросы по тегам