CSS Mesh Gradients

Share article: social.namesocial.namesocial.name

On Twitter, a guy named Toni Lijic was showing off how the new iOS version allows you to quickly and easily make mesh gradients as a background within iOS. It is a cool effect, and I wanted to see if I could recreate it using CSS.

Positioned Elements

I think the first step is to try and create a mesh gradient using a combination of four elements with blurs, which we can control their color dominace in a similar fashion to a mesh gradient.

HTML
        
    <div id="mesh-gradient" class="four-elements">
      <div class="element top-left"></div>
      <div class="element top-right"></div>
      <div class="element bottom-left"></div>
      <div class="element bottom-right"></div>
    </div>
        
      
SCSS
        
    #mesh-gradient.four-elements {
      width: 100%;
      height: 100%;
      display: grid;
      grid-template-columns: 1fr 1fr;
      grid-template-rows: 1fr 1fr;
      position: relative;
      background: linear-gradient(180deg, $apple-red 20%, lighten($apple-red, 5%) 35%, $apple-blue 70%);

      .element {
        position: absolute;
        border-radius: 100px;
        filter: blur(200px);
        transition: background 1s;
      }

      .top-left {
        top: 0;
        left: 0;
        width: 50%;
        height: 50%;
        background: $apple-red;
        opacity: 0;
        animation: four-elements 10s linear infinite;
        animation-delay: 0s;
      }

      .top-right {
        top: 0;
        right: 0;
        width: 50%;
        height: 50%;
        background: $apple-red;
        opacity: 0;
        animation: four-elements 10s linear infinite;
        animation-delay: -10s;
      }

      .bottom-left {
        bottom: 0;
        left: 0;
        width: 50%;
        height: 50%;
        background: $apple-blue;
        opacity: 0;
        animation: four-elements 10s linear infinite;
        animation-delay: 0;
      }

      .bottom-right {
        bottom: 0;
        right: 0;
        width: 50%;
        height: 50%;
        background: $apple-blue;
        opacity: 0;
        animation: four-elements 10s linear infinite;
        animation-delay: -12.5s;
      }

      @keyframes four-elements {
        0% {
          opacity:0;
          transform: scale(1);
        }
        50% {
          opacity: 1;
          transform: scale(2);
        }
        100% {
          opacity: 0;
          transform: scale(1);
        }
      }
    }
        
      

What we're doing is:

  • Setting a gradient background
  • Creating four elements, top two are red, bottom two are blue
  • Positioning them in the corners of the screen
  • Blurring them
  • Animating their opacity and scale
  • Adding an animation-delay to stagger the animations

This gives a nice flowing and repeatable effect which we can customize easily to any color combination. What is really interesting about this technique is that we can build up even more complicated meshes by adding more elements and colors.

To get a better sense of what is going on, you can remove the blur and see just the elements.

Here's the Sass that generated this.

SCSS
        
    #mesh-gradient.sixteen-elements {
      width: 100%;
      height: 100%;
      display: grid;
      grid-template-columns: 1fr 1fr 1fr 1fr ;
      grid-template-rows: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
      position: relative;

      // generate a linear gradient from the $mesh-colors
      background: linear-gradient(180deg, $orange 20%, $mint 50%, $purple 80%);

      $mesh-colors: ();

      // generate the colors with an HSL model
      @for $i from 1 through 32 {
        $hue: ($i - 1) * calc(360 / 32);
        $color: hsl($hue, 100%, 50%);
        $mesh-colors: map-merge($mesh-colors, ($i: $color));
      }

      $i: 1;
      @each $name, $color in $mesh-colors {
        $i: $i + 1;
        .element:nth-child(#{$i}) {
          background: $color;
          animation-delay: -#{$i * 0.625}s;
        }
      }

      .element {
        border-radius: 100px;
        animation: sixteen-elements 10s linear infinite;
      }

      &::after {
        width: 100%;
        height: 100%;
        content: '';
        position: absolute;
        top: 0;
        left: 0;
        background: rgba(black, 0.01);
        backdrop-filter: blur(20px);
        z-index: 1;
      }

      &.no-blur {
        
        &::after {
          display:none;
        }

      }

      @keyframes sixteen-elements {
        0% {
          opacity:0;
          transform: scale(1);
        }
        50% {
          opacity: 1;
          transform: scale(1.5);
        }
        100% {
          opacity: 0;
          transform: scale(1);
        }
      }
    }
    
      

Conclusion

So, this is a fun little experiment that I think could be used in a lot of different ways. I think it would be cool to see this used in a more subtle way as a background for a site. I think it could also be used as a loading animation or a background for a hero section. I think the possibilities are endless.

Vewrite - project management for technical writers

Project Management for Content Writers

Vewrite, project management tailored for writing teams, is launching soon. Make sure to sign up for the waitlist so that you can be notified when the product launches.

Check it out