Search code examples
csscss-animationscss-transitions

Why CSS background transition is not smooth?


I'm trying to animate my header background images but transition is not smooth like I saw in tutorial. (Ignore the gradient)

animation: slide 10s infinite;
@keyframes slide {
    0% {
        background-image: linear-gradient(
            rgba(0, 0, 0, 0.5),
            rgba(0, 0, 0, 0.5)
            ),url("imgs/header-1.jpg");
    }

    33% {
        background-image: linear-gradient(
            rgba(0, 0, 0, 0.5),
            rgba(0, 0, 0, 0.5)
            ),url("imgs/header-2.jpg");
    }

    67% {
        background-image: linear-gradient(
            rgba(0, 0, 0, 0.5),
            rgba(0, 0, 0, 0.5)
            ),url("imgs/header-3.jpg");
    }
}

Solution

  • UPD: Although according to documentation background-image property can not be animated, it may work in some environments. For example, the chrome browser allows to display transitions for background-image. However, it should include only url(/path/to/img) without any other properties. So in your case, just remove all the gradient definitions in keyframes, like this:

    @keyframes slide {
        0% {
            background-image: url("imgs/header-1.jpg");
        }
    
        33% {
            background-image: url("imgs/header-2.jpg");
        }
    
        67% {
            background-image: url("imgs/header-3.jpg");
        }
    }
    

    Reliable approach:

    Ok, so the main issue in your code is that background-image property should not be animated. However, it is possible to achieve the desired transition effect: you need to have multiple blocks with images placed one above another and just change their opacity each few seconds. The opacity property can be animated, so the general effect will be smooth.

    Here is an example:

    @keyframes fadeInOut {
      0% {
        opacity:1;
      }
      33% {
        opacity:0;
      }
      66% {
        opacity:0;
      }
      100% {
        opacity:1;
      }
    }
    
    .container {
      width: 400px;
      height: 400px;
      position: relative;
    }
    
    .animated-image {
      position: absolute;
      width: 100%;
      height: 100%;
      animation-name: fadeInOut;
      animation-timing-function: ease-in-out;
      animation-iteration-count: infinite;
      animation-duration: 9s;
      animation-direction: alternate;
    }
    
    .animated-image:nth-of-type(1) {
      animation-delay: 6s;
    }
    
    .animated-image:nth-of-type(2) {
      animation-delay: 3s;
    }
    
    .animated-image:nth-of-type(3) {
      animation-delay: 0s;
    }
    
    .image-1 {
      background-image: url(https://i.picsum.photos/id/299/400/400.jpg?hmac=JWLtcI8nmHDFvbS34TW5_MfzwOHSkXpWDLoXlNLyfAA);
    }
    
    .image-2 {
      background-image: url(https://i.picsum.photos/id/147/400/400.jpg?hmac=EtobpNQI_FLctas3TyOZMRQX362T9SCJs1rvd1S7d8Y);
    }
    
    .image-3 {
      background-image: url(https://i.picsum.photos/id/906/400/400.jpg?hmac=VO0HSf238e6GuEC7_yx1TKPO9Z0iZgl7BgmoWyjNbXo);
    }
    <div class="container">
      <div class="animated-image image-1"></div>
      <div class="animated-image image-2"></div>
      <div class="animated-image image-3"></div>
    </div>

    Note, that you can do this trick with any type of HTML element, so you may use img tag instead of divs with background-image if you like.