Surfin' Safari

CSS3 Gradients

Posted by Simon Fraser on Friday, January 14th, 2011 at 1:08 pm

Introduction

WebKit paved the way for gradients in CSS by adding support for -webkit-gradient back in early 2008, and they’ve become widely used since their introduction.

Over the past several months, the CSS Working Group has had extended discussions about making the gradient syntax easier to use, and recently Tab Atkins included a proposal in the latest draft of the Image Values and Replaced Content module. WebKit and Mozilla have now implemented this proposal so that web authors can experiment with it, and provide feedback to the Working Group. Note that the proposal is still an editor’s draft, which means that it’s still possible, and even likely to change due to user feedback.

The main goal of the new syntax is simplicity; it’s now really easy to code up common gradients, as you’ll see in the examples below. A secondary goal was to specify something where implementations were compatible across browsers.

If you’re not already running one, go and grab a recent nightly build so that you can see the examples in this post.

Here are some simple examples (note that all these examples are resizable, so you can see how resizing the box affects the gradients):

background-image: -webkit-linear-gradient(red, green, blue);
background-image: -webkit-radial-gradient(circle, white, black);

Don’t forget that gradients are a type of generated image, not a property. This means that you can use them anywhere you’d use a url(image.png).

The New Gradient Syntax

The new syntax has four gradient functions:

  • linear-gradient()
  • radial-gradient()
  • repeating-linear-gradient()
  • repeating-radial-gradient()

The names are pretty self-explanatory, but I’ll say more about repeating gradients later. One nice thing is that the syntax for the repeating and non-repeating variants is identical.

Because this specification is still in draft form, we’ve prefixed these gradient functions with -webkit- prefix. Later when the specification is out of the draft phase you’ll be able to use them without the prefix.

Linear Gradients

Since filling the element’s box is the most common use for gradients, this is the standard behavior for linear gradients. All that you have to think about is what direction you want the gradient to run in.

There are two ways to specify this. First, you can specify the side or corner where you want the gradient to start:

-webkit-linear-gradient(left, white, black)
-webkit-linear-gradient(top right, white, black)

You can even omit the first argument, and it will default to top, giving a vertical gradient.

In the second form, you can specify the angle of the gradient axis:

-webkit-linear-gradient(135deg, white, black)

Angles run counter-clockwise, and 0deg is to the right. Note how in all these cases, the gradient is just big enough to fill the box.

Radial Gradients

Radial gradients are a little more complex, because there are more options about how to fill the box. In its simplest form, the gradient is centered in the box, and is large enough to fill it to the corners:

-webkit-radial-gradient(white, black)

This is equivalent to -webkit-radial-gradient(center, ellipse cover, white, black). That optional first argument, center, can also be a point (just like background-position), which allows you to put the origin somewhere else:

-webkit-radial-gradient(10% 30%, white, black)

The argument after the position specifies the shape and size of the gradient, in one of two ways. The first uses some keyword for the shape (circle, ellipse) and size (closest-side, closest-corner, farthest-side, farthest-corner, contain, cover) which are self-describing. For example:

-webkit-radial-gradient(30% 30%, closest-corner, white, black)
-webkit-radial-gradient(30% 30%, circle closest-corner, white, black)

If you want to, you can specify the ending radius of the gradient explicitly, and separately for the horizontal and vertical axes:

-webkit-radial-gradient(center, 5em 40px, white, black)

Color Stops

It’s very easy to specify color stops with the new gradients; in the simplest case, you can just supply a list of colors:

-webkit-linear-gradient(left, red, green, blue)

This results in the colors being spread out evenly over the gradient. If you like, you can position specific stops, and let the browser distribute the rest between those:

-webkit-linear-gradient(bottom left, red 20px, yellow, green, blue 90%)

Those lengths are along the gradient axis, which may be diagonal; percentages are relative to that diagonal length.

Color stops at the same position result in sharp color changes:

-webkit-linear-gradient(top left, red, yellow, green 60%, purple 60%, blue)

Repeating Gradients

The repeating forms, repeating-linear-gradient(), and repeating-radial-gradient(), have exactly the same syntax as the simple forms, but fill in the entire gradient by repeating the stops:

-webkit-repeating-linear-gradient(left, red 10%, blue 30%)

The stops are repeated by just aligning them end-to-end, which often results in a sharp boundary. You can avoid this by repeating the last color:

-webkit-repeating-radial-gradient(top left, circle, red, blue 10%, red 20%)

Changes from -webkit-gradient

You should be able to recreate most of the gradients you made with -webkit-gradient with this new syntax, but there are some changes to be aware of.

First, -webkit-gradient uses a two-point syntax that lets you explicitly state where a linear gradient starts and ends. linear-gradient does away with this in favor of convenient box-filling behavior. If you really want the gradient to stop before the edges of the box, you can do so via color stop placement.

Similarly, radial-gradient no longer allows you to specify different start and end points for radial gradients, so the new radial gradients are always concentric. You can, however, produce elliptical gradients with the new syntax, which was not possible with -webkit-gradient.

So is -webkit-gradient going away? Certainly not! We’ll maintain support for -webkit-gradient for the foreseeable future for all the existing content out there that uses it.

Please Give Feedback

To reiterate, we’ve implemented support for these new gradients so that you, as web developers and authors, can give feedback. The correct forum for discussion of the gradient syntax and behavior is the www-style mailing list. If you find a bug in the implementation, please file a bug at bugs.webkit.org.

14 Responses to “CSS3 Gradients”

  1. CyberSkull Says:

    I really like it when you guys make these exelent blog posts about WebKit features. Keep ‘em coming! :D

  2. JAB Creations Says:

    I think WebKit has made the most progress implementing useful CSS3 properties though I’m still not sure what exactly was introduced in Safari 5.0. I’d really appreciate it if you folks could please post a blog entry with an overview of the changes. Regardless gradients are awesome because of the ability to implement a lot of visual design with very little bandwidth.

  3. lensco Says:

    Really glad about this new syntax. I always had to copy an existing gradient from my stylesheets to get the right syntax. This one, I can remember!

  4. JoeP Says:

    Great news about the syntax! Removing proprietary syntax is one of the major things that’d make my life easier; the other being speeding up time to improve the enterprise upgrade cycles in order to finally eliminate IE6.

  5. bfred.it Says:

    You are ridiculous. So we’re basically going towards this in our CSS:

    filter: progid:DXImageTransform.Microsoft.Gradient(StartColorStr=’#FFFFFF’, EndColorStr=’#000000′);
    -ms-filter: progid:DXImageTransform.Microsoft.Gradient(StartColorStr=’#FFFFFF’, EndColorStr=’#000000′);
    background-image: -webkit-gradient(linear, color-stop(0, white), color-stop(1, white))
    background-image: -webkit-linear-gradient(white, black);
    background-image: -moz-linear-gradient(white, black);
    background-image: linear-gradient(white, black);

    Don’t you just realize this is ridiculous?
    Can’t you just support mozilla’s prefix rather than adding yet another function that you (developers) and us (css coders) will have to support for years to come?

    Many other CSS3 features have the same syntax in multiple browsers, still we have to write the same identical crap over and over, RATHER THAN doing like so:
    -(the prefix of the vendor who introduced this first)-border-radius: 10px;

    Or just
    -beta-border-radius: 10px; /* A List Apart’s idea */

    No – you just have to use custom-named functions to support your ego.

    If YOU VENDORS didn’t make such ridiculous mistakes, we could “just” use:

    filter: progid:DXImageTransform.Microsoft.Gradient(StartColorStr=’#FFFFFF’, EndColorStr=’#000000′);
    background-image: -beta-gradient(linear, color-stop(0, white), color-stop(1, white))
    background-image: -moz-linear-gradient(white, black);
    background-image: linear-gradient(white, black);

    Those might just be 2 lines you saved, but then repeat that for every function for every elements that uses it in your page and you’ll realize that 10% of your CSS is redundant.

    - a web designer who’s tired of nonsense

  6. traq Says:

    @ bfred.it:

    I agree with your frustration (especially about having multiple properties / syntaxes for a _single_ browser — I don’t see _revised_ vendor properties being practical at all), but asking all “beta” implementations support the same property name “{first-vendor-prefix}” or “-beta”) is even less practical.

    The whole reason there is a prefix in the first place is that the vendors are quite likely to have different implementations. Major or minor differences, it’s hardly an “ego” issue. Without vendor prefixes, we’d be forced back into using browser sniffing to get just about _anything_ to display correctly.

  7. mdriftmeyer Says:

    traq is correct about different implementations on the back end.

    However, you’re complaining about adding a few lines of code which if you put in a master .css file and import your custom files specific to your site development [a normal process] this somehow puts undue levels of work on your part?

    I’d rather have vendor specific prefixes for functionality that may or may not even be working when one is developing and testing across multiple platforms. It’s much easier to comment out those areas and continue testing than to hope every vendor is up-to-speed for specific areas of CSS functionality.

    The only way -gradient will ever work is if they are all using the same backend code to produce the desired result.

  8. grand_troll Says:

    What is pleasant is to read “WebKit AND Mozilla have now implemented this proposal “. See 2 teams work together help to believe that our subject here will become a standard.

  9. Levi Figueira Says:

    As much as I want to agree with bfred.it about the nuisance of extra code, I don’t get why he’s complaining on the Webkit blog, which as long been the best and most advanced CSS3 engine out there. Why don’t you complain to Microsoft for that silly insanely long line you have to add for their sub-par browsers? Why doesn’t Mozilla join Webkit instead? I’m fine with a -moz and a -webkit line… I don’t do anything fancy for IE (unless it somehow reads the CSS3 properties). I do 3 lines for border-radius for example: -webkit, -moz and border-radius. Anyone else can get a decent browser… and it’s not IE.

    Now, do us all “web designers who are tired of nonsense” a favor and take your great opinion and go put it in the Internet Explorer/Trident developer blog. It makes much more sense there. :)

  10. bfred.it Says:

    Levi, I complained here because the Webkit team implemented the exact same syntax (I just double-checked on developer.mozilla.org) with a different name. This also sparked an argument about browsers vendors in general, who keep doing this over and over. I’m pro-prefixes but I’m against the practice described in my comment.
    I’m sure MS knows how we feel, they just don’t care. Apparently they are going to support “border-radius” without prefix, and if the draft changes, we’re going to be fighting IE9 for the next 10 years the same way we did with IE6.

    traq: different implementation = different prefix (as in my second example), same implementation should be same prefix

    mdriftmeyer: I thought more code = more code to maintain, but I guess it’s not your case?

  11. rchl Says:

    Mozilla and Webkit implementations are not really the same. Mozilla impl is based on slightly older spec thus supports center bg-position for gradient line (pixel positioning, support for center keyword and more). That makes these implementations incompatible and can’t be shipped with same prefix.

    Discussion about prefixes is old thought and does not really fit this post.

  12. Peter N Lewis Says:

    Is there any way to make the end gradient relative to the end position? Eg, say I wanted a gradient to be from 20px to size-20px? I know I could use 10% to 90%, but that only works for percentages.

  13. mdriftmeyer Says:

    @mdriftmeyer: I thought more code = more code to maintain, but I guess it’s not your case?

    Seriously? Those includes are so difficult to maintain from the server, right? Not.

  14. jocphone Says:

    Hi, how about we have some other directions for gradients?

    All I ever see is linear and radial (radius to centre).

    A gradient which ran around a circle would be really useful i.e. the colour changes follow the circumference
    of the circle. Also a gradient which allowed you to specify a path for the colours to follow would be awesome.