4

I have a div background pan that I want to slow on hover:

@keyframes backgroundScroll {
  0% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0% 50%;
  }
}
div {
  width: 30vw;
  height: 30vh;
  background: repeating-linear-gradient(
    45deg,
    #EE0000,
    #EE0000 10px,
    #990000 10px,
    #990000 20px
  );
  background-size: 150%;
  background-position: 50% 50%;
  animation: backgroundScroll 3s linear infinite;
}
div:hover{
  animation: backgroundScroll 20s;
}
<div></div>

In theory, something like this would work, but it doesen't retain the state. I went digging and found it is possible to retain the animation state: StackOverflow-Change Animation speed on hover. After disection, I found it uses an illusion, which reduced to my purposes is this. I am wondering if there is a way to apply this to the original code.

henxdl
  • 118
  • 14

6 Answers6

6

One posibility is to set 2 different animations, and pause one of them

@keyframes ScrollX {
  0% {
    background-position-x: 0px;
  }
  100% {
    background-position-x: -28px;
  }
}
@keyframes ScrollY {
  0% {
    background-position-y: 0px;
  }
  100% {
    background-position-y: -28px;
  }
}

div {
  width: 30vw;
  height: 30vh;
  background: repeating-linear-gradient(
    45deg,
    #EE0000,
    #EE0000 10px,
    #990000 10px,
    #990000 20px
  );
  background-size: 150% 150%;
  background-position: 50% 50%;
  animation: ScrollX 1s linear infinite, ScrollY 1.5s linear infinite paused;
}
div:hover{
  animation: ScrollX 1s linear infinite, ScrollY 1.5s linear infinite;
}
<div></div>
vals
  • 61,425
  • 11
  • 89
  • 138
2

I managed to achieve the visual effect by wrapping it in another div (overflow: hidden) and applying a hover animation to the scrolling div itself.

The problem with this solution: it's not just the background that's scrolling. Any of the div's contents would also be scrolling on hover. So depending on what you're going to use it for, it might not be perfect.

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

  100% {
    background-position: 0% 50%;
  }
}

@keyframes scrollX {
  0% {
    margin-left: 0;
  }

  100% {
    margin-left: -30vw;
  }
}

.wrapper {
  width: 30vw;
  height: 30vh;
  overflow: hidden;
}

.scrolling {
  width: 90vw;
  height: 30vh;
  background:
    repeating-linear-gradient(45deg,
      #EE0000,
      #EE0000 10px,
      #990000 10px,
      #990000 20px);
  background-size: 150%;
  background-position: 50% 50%;
  animation-name: backgroundScroll, scrollX;
  animation-duration: 9s, 10s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  animation-play-state: running, paused;
}

.scrolling:hover {
  animation-play-state: running;
}
<div class="wrapper">
  <div class="scrolling">
  </div>
</div>
drak
  • 302
  • 8
2

A similar idea to @vals answer but I will use translation to achieve it. I used a common multiplier so you can easily control the speed. The first animation need a number N while the second one need to use a number with an opposite sign to decrease the speed.

Below I am using -3 and by adding 2 to it I get -1 so I go from -3 to -1

div {
  width: 30vw;
  height: 30vh;
  position:relative;
  z-index: 0;
  overflow: hidden;
}
div:before {
  content:"";
  inset: 0 -100% 0;
  position: absolute;
  background: repeating-linear-gradient(
    45deg, #EE0000 0 10px, #990000 0 20px
  );
  --m: (1.414 * 20px); /* this is the multiplier for the speed */
  animation: 
   main  1s linear infinite, 
   brake 1s linear infinite paused;
}
div:hover:before {
   animation-play-state: running;
}

@keyframes main {
  to {
    transform: translate(calc(-3* var(--m)));
  }
}
@keyframes brake {
  to {
    translate: calc(2* var(--m)) 0;
  }
}
<div></div>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
1

Do mean Like this :

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

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

div {
  width: 30vw;
  height: 30vh;
  background: repeating-linear-gradient(
    45deg,
    #EE0000,
    #EE0000 10px,
    #999900 10px,
    #999000 20px
  );
  background-size: 150%;
  background-position: 50% 50%;
  animation: backgroundScroll 3s linear infinite;
}

div:hover {
  animation: backgroundScrollHover 20s linear infinite;
}
<div></div>
Zakaria Zhlat
  • 320
  • 1
  • 6
  • 21
  • Unfortunately, this solution does not address the issue of the place not being retained. On hover, you can see that the stripes move slightly from their original position. I would like it to retain its original position. – henxdl May 31 '23 at 20:53
1

Do you want like this?

just add animation: none;

or

  animation-play-state: paused;
  animation-fill-mode: forwards; 

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

div {
  width: 30vw;
  height: 30vh;
  background: repeating-linear-gradient(
    45deg,
    #EE0000,
    #EE0000 10px,
    #990000 10px,
    #990000 20px
  );
  background-size: 150%;
  background-position: 50% 50%;
  animation: backgroundScroll 3s linear infinite;
}

div:hover {
  animation: none;

}
<div></div>
0

Is this what you were looking for?

:root {
  --speed: 3s;
}

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

div {
  width: 30vw;
  height: 30vh;
  background: repeating-linear-gradient(
    45deg,
    #EE0000,
    #EE0000 10px,
    #990000 10px,
    #990000 20px
  );
  background-size: 150%;
  background-position: 50% 50%;
  animation: backgroundScroll var(--speed) linear infinite;
}

div:hover{
  --speed: 15s;
}
<div></div>
Connie
  • 251
  • 4
  • 17