Search code examples
htmlcssanimationbackground-imagelinear-gradients

Generating an animated rainbow border


I've been using the background-image CSS property to create a rainbow border like this:

.rainbow {
  border: double 0.3em transparent;
  border-radius: 10px;
  background-image: linear-gradient(white, white), 
  linear-gradient(to right, rgb(235, 50, 235), rgb(82, 82, 209));
  background-origin: border-box;
  background-clip: content-box, border-box;
}
<div class="rainbow">Example</div>

And would like to animate it. Is it possible to animate background-image, and if so how could it be used?


Solution

  • I was able to get this working by animating the background-position as an offset, there is a very slight flicker when the animation resets on my browser, but you can make it less frequent by using larger vh values, and it's only really noticeable on thick elements (or when you have stuff like border 3em)

        /*animate the background gradient position, use vh so that start/end syncs up viewport horizontal*/
    @keyframes rainbow {
        from {background-position: -100vh 0}
        to {background-position: 100vh 0}
    } 
    
    /*compatibility*/
    @-moz-keyframes rainbow {
        from {background-position: -100vh 0}
        to {background-position: 100vh 0}
    }
    @-webkit-keyframes rainbow {
        from {background-position: -100vh 0}
        to {background-position: 100vh 0}
    }
    @-ms-keyframes rainbow {
        from {background-position: -100vh 0}
        to {background-position: 100vh 0}
    }
    @-o-keyframes rainbow {
        from {background-position: -100vh 0}
        to {background-position: 100vh 0}
    }
    
     .rainbow {
      border: double 0.3em transparent;
      border-radius: 10px;
         /*added a colourstop here, without the third colourstop you get a hard edge*/
      background: linear-gradient(white, white), 
      repeating-linear-gradient(to right, rgb(82, 82, 209),rgb(235, 50, 235), rgb(82, 82, 209));
      background-origin: border-box;
      background-clip: content-box, border-box;
    
    
                animation-name: rainbow;
                animation-duration:  3s;
    
                /*set animation to continue forever, and to move at a single rate instead of easing*/
                animation-iteration-count: infinite;
                animation-timing-function: linear;
    }
    

    Hope this helps!