Bulletproof and fast css gradients

I am daring to claim that I have found the best bulletproof way to create css3 background gradients. It is the best because it guarantees that extra http requests are not made unless needed and bulletproof because it works in every browser falling back to a normal background-image based gradient if necessary.

UPDATE: Added new rules for IE10 and Opera 11.10!

For the impatient here is the code:

background: #FFF url('grad.png') repeat-x left top; /* fallback to image */
background-image: none,url('grad.svgz'); /* gziped svg for Opera < 11.10 and IE9, base64 encoding desirable */
background-image:none\9; /* IE hack to prevent ie from needlessly downloading the fallback image. It will use the filter instead*/
background-size: 100% 100%; /*scale background image if possible */
background: -webkit-gradient(
linear,
left bottom,
left top,
color-stop(0, #FFF),
color-stop(1, #000)
); /* For older Safari / Chrome */
background: -moz-linear-gradient(
bottom,
#FFF 0%,
#000 100%
); /* Firefox 3.6+ */
background: -webkit-linear-gradient(
bottom,
#FFF 0%,
#000 100%
); /* Recent Chrome and Safari */
background: -o-linear-gradient(
bottom,
#FFF 0%,
#000 100%
); /* Opera 11.10+ */
background: -ms-linear-gradient(
bottom,
#FFF 0%,
#000 100%
); /* IE10 */
background: linear-gradient(
bottom,
#FFF 0%,
#000 100%
); /* Current standard if anyone ever supports it */
filter: progid:DXImageTransform.Microsoft.gradient(endColorstr='#ffffff', startColorstr='#000000'); /* for IE */

.gte9 tag {
filter: none;
}
You can see the demo page here.

UPDATE Sept 25, 2011

Now that IE9 is out some slight changes should be made to make this just a little bit better. IE9 added support for svg backgrounds so it behaves just like Opera did with this CSS. Except now Opera has added support for css gradients using the -o prefix since version 11.10 so a rule for that was added. The filter works fine for IE9 and a conditional comment style rule could be added to prevent IE9 from downloading the svg file and just rely on the filter property but I feel as this is not ideal. First of all filter is old and in the past has been known to cause performance penalties. The real deal breaker is that filter does not play well with the new border-radius css3 property with IE9 has added support for. Using gradients with the filter property combined with border radius will cause the background to spill out of the rounded corners and not look very good. If SVG backgrounds are used it works fine. So I recommend using base64 encoded data uri to save a request to the svg file and using condition comments to add a filter: none rule for IE9. NOTE: It doesn’t work to base64 encode a svgz file only svg will work.

Except for the fallback image and the svg image for Opera, CSS gradients can easily be created using the Ultimate CSS gradient generator. The generator will give you a good start but needs to be expanded to be completely bulletproof.

The first line:

background: #FFF url('grad.png') repeat-x left top;
Uses a common 1 px wide 50px high image with a gradient created with the GIMP going from black to white. If you want to ensure the gradient looks exactly the same in every browser you could first create the gradient with CSS and then take a screenshot of it in Firefox or Chrome.

SVG for Opera

background-image: none,url('grad.svgz');
This line is for Opera and other browsers that support svg but not true CSS gradients. How to create the svg file I will cover later. The important bit that other bulletproof techniques leave out is the “none,” part. This is the scheme for specifying multiple CSS backgrounds which means that browser that don’t support multiple backgrounds will ignore this line and the svg image. It’s a pretty safe bet that if a browser doesn’t support svg images it won’t support multiple backgrounds so this works very well. IE, However, interprets this line a little differently but it’s to our advantage. It parses up to the comma and ignores the rest effectively setting the background to none. This is a good thing since it prevents IE from downloading the fallback background image and just using the filter.

For Webkit

background: -webkit-gradient(
linear,
left bottom,
left top,
color-stop(0, #FFF),
color-stop(1, #000)
);

The syntax is as follows:

-webkit-gradient(<type>, <point> , <point> [, <stop>]*)

<type> is either linear or radial. For now I’m just going to talk about linear gradients. In another article I’ll describe how to make cool list item bullets using radial gradients. The <points> are the starting points and ending points respectively. Then can be specified using x y coordinates using px or % units (ie. 0px 10px) or the keywords top, left, right or bottom. One or more < stops> are used to specify the color of the gradient.  Such as color-stop(x, <color>), where x is a decimal between 0 and 1, 0 being the color at the starting pint and 1 being the color at the ending point and anything else being the colors in between . <color> is any valid css color., clever things can be achieved using rgba style colors. Webkit has recently introduced a new syntax for gradients that are similar to the -moz style. They are outlined on webkit’s blog. It is recommended that you still include the old style because browser that support the new style are not yet widely deployed.

For Firefox

background: -moz-linear-gradient(
bottom,
#FFF 0%,
#000 100%
); /* Firefox 3.6+ */

Firefox’s syntax is:

-moz-linear-gradient( [<point> || <angle>,]? <stop>, <stop> [, <stop>]* )

Point is the starting position of the gradient specified in px, %, or the keywords left, right, top, bottom or middle. Unless defined angle will be 180deg, -45deg would make a gradient from one corner to the next. Multiple color stops are specified with any valid css color and a percentage value. See mozilla’s site for complete details.

The dreaded Internet Exploder

filter: progid:DXImageTransform.Microsoft.gradient(endColorstr=’#ffffff’, startColorstr=’#000000′); /* for IE */

IE uses a very basic propriety feature that only supports linear gradients with two colors in the horizontal or vertical direction. However it is supported in IE 5.5+ which is rather impressive. All that needs specified is the start color and end color. You can use size hex digits or 8 which is similar to rgba where the first two hex digits are the alpha value. So you can actually create a background that is half transparent with:
filter: progid:DXImageTransform.Microsoft.gradient(endColorstr='#88FF0000', startColorstr='#88FF0000');
This would create red background that is half transparent.

There is some concern that using IE filters can cause performance problems with rendering the page and may not actually be the best. I have done a few tests using webpagetest.org. Here is a test of the demo page using a background image. The median load time is 0.555s. Another test using IE filter gradients. The median load time is 0.537s. The demo page uses several very large gradients and they load 18ms faster than the image based gradients. The difference would probably be much greater with a complex page with several different kinds of gradients.

So filter gradients don’t pose much of a performance penalty but they can cause fonts to be displayed without anti-aliasing also known as cleartype. This apparently is a change the IE developers in their wisdom decided to make with IE7 and kept in IE8. Elements with a css filter don’t use cleartype so the fonts look terrible. There is a easy work around that works in IE8 but not IE7. Simply create an inner div or other element inside the element with the filter gradient, then give this div “position: relative;”. The fonts will then be rendered correctly. It is also worth noting that gradients will not show up in IE6 or 7 unless the element haslayout. This can easily be fixed by giving the element a width or using the zoom: 1; property.

Finally to create the svg image, open a text editor and enter:

<svg xmlns="http://www.w3.org/2000/svg" version="1.0"> <defs> <linearGradient x1="0" y1="0" x2="0" y2="100%"> <stop offset="0%" style="stop-color: #000000;"/> <stop offset="100%" style="stop-color: #ffffff;"/> </linearGradient> </defs> <rect x="0" y="0" fill="url(#gradient)" width="100%" height="100%" /></svg>

Save as grad.svg. The syntax is similar to CSS3. x1, y1, x2, y2 are the starting and ending points. The stop tags are the stop colors. Mostly the only browser that will use this are Opera and Ios before v4. It does not save an http request (unless you convert it to a base64 data url) but it does provide true flexible gradients. Optionally you can gzip the file with gzip and change the extension to svgz which saves a few bytes. Interestingly the resulting file was 219 bytes which is actually larger than the 1x50px png file which was 178 bytes. For svg’s to work they must be sent with the “Content-type: image/svg+xml” header or they will just be interpreted as plain text which is not what we want. Usually webserver will send them correctly but if not you can fix apache by adding this to the .htaccess file:

AddType image/svg+xml .svg

So there you have flexible and fast css gradients which use a minimum of http requests. Please leave a comment if you have any success using this method. Next I will look at the cool things you can do with radial gradients.

No related posts.

This entry was posted in css3, site performance and tagged , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

2 Comments

  1. ainos
    Posted April 10, 2012 at 12:01 pm | Permalink

    hi there! you write “Forefox” instead of Firefox. Thank you so much!! The “position: relative;” solve my problem of the ugly text! :)

  2. admin
    Posted April 10, 2012 at 8:34 pm | Permalink

    I fixed the typo, thanks for the feedback.

One Trackback

  1. [...] link: Bulletproof and fast css gradients Share and [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>