Animate Background Gradients with CSS3

Posted

It’s been a little while since I had some fun with CSS on my blog, time to fix that. Today I want to look into putting together some buttons with CSS3. Now, this is nothing new of course. I’m sure there are hundreds of articles out there talking about what you can do with CSS3 to make some great buttons that don’t lean on images for support. Indeed I have been using CSS to build interface pieces for quite some time now and as a result I have come to favor certain styles and ways of going about my button creation. Let’s look into some of the pros and cons offered by CSS3.

Power and Pitfalls

Buttons seem like one of those things that CSS3 was made for. We have a wide array of new(ish) tools to throw at our interfaces now, rounded corners, text shadows, gradients, transitions, and box shadows to name some of the more popular options. It’s tempting to use all of these at once, after all it’s pretty easy these days to put together quite a bit of fancy code in no time thanks to gradient generators and prefixing tools. Of course at the same time this can turn into some pretty sloppy code with questionable maintainability:


background-color: #f0f0f0; 
background-image: -moz-linear-gradient(top, #fff, #E6E6E6); 
background-image: -ms-linear-gradient(top, #fff, #E6E6E6); 
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fff), to(#E6E6E6)); 
background-image: -webkit-linear-gradient(top, #fff, #E6E6E6); 
background-image: -o-linear-gradient(top, #fff, #E6E6E6); 
background-image: linear-gradient(top, #fff, #E6E6E6); 
background-repeat: repeat-x; 
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); 

I pick on the background gradient because my love affair with it has been short and is becoming tepid. While I still prefer using CSS3 for my gradients over images in most cases, it’s hard to argue that the above code is easy on the eyes. Of course background gradients have another downfall too, one that is especially frustrating with buttons. That is, at the time of this writing the background-image property is not supported by CSS3 transitions. So if we use gradients to build buttons we tend to be stuck with that gradient for different button states. So what’s a designer to do?

Animating Gradient Backgrounds

My fallback (or fall-forward) for this has been using box-shadow to create a gradient. The box-shadow property has several advantages here. First, the code is consistent between browsers. While we still need to do some prefixing to support all browser types, we have clearly reached a standard format between Mozilla and Webkit browsers that will likely reach the final recommendation stages before gradients. In addition, box-shadow gets along well with transitions, meaning we gain the ability to animate. Our trade-off here is that we are still faking a gradient, box-shadow will take a lot more trial and error to generate a smooth gradient from one area of an element to another. Lets start by taking a look at the finished product:

There is a lot going on here in terms of CSS but lets just take a look at the interesting part, the box-shadow:

    
 
box-shadow: 0 8px 3px -4px rgba(0, 0, 0, 0.2), 
            inset 0 25px 20px -10px rgba(255, 255, 255, 0.3), 
            inset 0 -15px 20px -10px rgba(0, 0, 0, 0.15); 

We have 3 different shadows in here. The first is the most boring, it’s simply the drop shadow that falls below the button however it does bring up a somewhat interesting point. I see a lot of designers neglect the fourth value set of box-shadow which is, in this case, -4px. This sets the size of the shadow relative to the object it is attached to, so in our example the drop shadow will be 4 pixels smaller than the button it falls off of. I think this gives a good effect of perspective and will come in handy when we animate things.

I’ve found that the fourth box-shadow property also serves to soften things up a little bit,which plays a much larger role in our two additional shadows. Both of the other shadows are inset, the first on the top of the button and the second on the bottom. I have always been a fan of using rgba white and black, not just for shadows but also gradients and backgrounds, I think it gives the designer a lot of flexibility and makes for some preset CSS styles that can be applied to myriad objects. If you want to go in depth into that sort of thing check out my article on Smashing Magazine. Here we have applied a light “shadow” to the top and a dark one to the bottom.

Again, I am using the fourth box-shadow value to soften up the shadow on either side of the button which helps it to run from top to bottom more like we would expect a gradient to. When we work with rounded corners and inset box shadows the shadow will curve with the button. In most cases that is the desirable behavior but in this case I wanted to reduce that rounded look from my shadows. Now lets take a look at the CSS for the hover state:

 
box-shadow: 0 2px 1px rgba(0, 0, 0, 0.35), 
            inset 0 20px 20px -10px rgba(0, 0, 0, 0.15), 
            inset 0 -15px 20px -10px rgba(255, 255, 255, 0.3); 

transition: box-shadow 0.15s linear; 

Keep in mind that I have stripped out the prefixed versions of everything for the sake of brevity. All I’ve really done here is reversed each of the box-shadows and put the lighter one on the bottom and the darker one on top. At the same time I’ve taken the first shadow brought it closer to the button, sharpened it up, and changed the size relation. The transition property is pretty straight forward.

So there we have it. A quick and dirty look at faking animated background gradients. These properties can easily be applied to any background color too which makes this practice pretty flexible. If you want to get more in depth check out the demo page. Also, for giggles here is the entirety of my sloppy CSS:

   
 
button { 
    display: inline-block; 
    padding: 0 35px; 
    text-align: center; 
    text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.3); 
    vertical-align: middle; 
    cursor: pointer; 
    line-height: 40px; 
    border: 1px solid #0a72aa; 
    border-top: 1px solid #169abb; 
    background: #1eafd3; 
    color: #f0f0f0; 
    font-size: 16px; 

    -webkit-border-radius: 20px; 
    -moz-border-radius: 20px; 
    border-radius: 20px; 

    -webkit-box-shadow: 0 8px 3px -4px rgba(0, 0, 0, 0.2), 
                        inset 0 25px 20px -10px rgba(255, 255, 255, 0.3), 
                        inset 0 -15px 20px -10px rgba(0, 0, 0, 0.15); 

    -moz-box-shadow: 0 8px 3px -4px rgba(0, 0, 0, 0.2), 
                     inset 0 25px 20px -10px rgba(255, 255, 255, 0.3), 
                     inset 0 -15px 20px -10px rgba(0, 0, 0, 0.15); 

    box-shadow: 0 8px 3px -4px rgba(0, 0, 0, 0.2), 
                inset 0 25px 20px -10px rgba(255, 255, 255, 0.3), 
                inset 0 -15px 20px -10px rgba(0, 0, 0, 0.15); 
} 

button:hover { 
    text-decoration: none; 

    -webkit-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.35), 
                        inset 0 20px 20px -10px rgba(0, 0, 0, 0.15), 
                        inset 0 -15px 20px -10px rgba(255, 255, 255, 0.3); 

    -moz-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.35), 
                     inset 0 20px 20px -10px rgba(0, 0, 0, 0.15), 
                     inset 0 -15px 20px -10px rgba(255, 255, 255, 0.3); 

    box-shadow: 0 2px 2px rgba(0, 0, 0, 0.35), 
                inset 0 20px 20px -10px rgba(0, 0, 0, 0.15), 
                inset 0 -15px 20px -10px rgba(255, 255, 255, 0.3); 

    -webkit-transition: box-shadow 0.15s linear; 
    -moz-transition: box-shadow 0.15s linear; 
    -ms-transition: box-shadow 0.15s linear; 
    -o-transition: box-shadow 0.15s linear; 
    transition: box-shadow 0.15s linear; 
} 

2 Responses to “Animate Background Gradients with CSS3”

Leave a Reply

XHTML: You can use these tags: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>