CSS Gradients via Canvas
Switch branches/tags
Nothing to show
Pull request Compare This branch is even with westonruter:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


CSS Gradients via Canvas

In a current project an old project when I worked at Shepherd Interactive, certain page elements were designed with background gradients. Given the desire to minimize the need for externally-loaded background images wherever possible, I thought this would be a great opportunity to play around with WebKit's proposed CSS Gradients, which are natively supported by Safari, Chrome, and other WebKit-based browsers. In being a WebKit proposal, however, CSS Gradients are not (yet) natively supported in other rendering engines as used by Firefox, Opera, and Internet Explorer.

CSS Gradients via Canvas provides a subset of WebKit's CSS Gradients proposal for browsers that implement the HTML5 canvas element. To use, just include css-gradients-via-canvas.js (12KB) anywhere on the page. Unlike WebKit, this implementation does not currently allow gradients to be used for border images, list bullets, or generated content. The script employs document.querySelectorAll()—it has no external dependencies if this function is implemented; otherwise, it looks for the presence of jQuery, Prototype, or Sizzle to provide selector-querying functionality.

The implementation works in Firefox 2/3+ and Opera 9.64 (at least). Safari and Chrome have native support for CSS Gradients since they use WebKit, as already mentioned. Beginning with version 3.6, CSS Gradients are also natively supported by Firefox and this implementation will defer in such case; note that you will need to specify two separate background CSS properties, one with -webkit-gradient and another with -moz-linear/radial-gradient which has a different syntax). This implementation does not work in Internet Explorer since IE does not support Canvas, although IE8 does support the data: URI scheme, which is a prerequisite (see support detection method). When/if Gears's Canvas API fully implements the HTML5 canvas specification, then this implementation should be tweakable to work in IE8. In the mean time, rudimentary gradients may be achieved in IE by means of its non-standard gradient filter.

CSS Gradients via Canvas works by parsing all stylesheets upon page load (DOMContentLoaded), and searches for all instances of CSS gradients being used as background images. The source code for the external stylesheets is loaded via XMLHttpRequest—ensure that they are cached by serving them with a far-future Expires header to avoid extra HTTP traffic. The CSS selector associated with the gradient background image property is used to query all elements on the page; for each of the selected elements, a canvas is created of the same size as the element's dimensions, and the specified gradients are drawn onto that canvas. Thereafter, the gradient image is retrieved via canvas.toDataURL() and this data is supplied as the background-image for the element.

A few notes regarding interactivity with this implementation: CSS gradients will not be applied to elements dynamically added after DOMContentLoaded. Additionally, each element that has a CSS gradient applied to it gets assigned a method called refreshCSSGradient(); at any time, this method may be invoked to redraw the gradient on a given element. This is especially useful (and necessary) when an element's size dynamically changes, for example as the result of some user interaction. Likewise, it is important to note that it will not work to rely on event handlers to invoke refreshCSSGradient() on elements whose style is changed by CSS rules with pseudo-selectors like :hover and :active; this is because event handlers are fired before the rule's style changes are applied to the element. Toggling an element's class name by scripting is how you can assure that its style will be changed before calling refreshCSSGradient().

See examples.


Updated license to be GPL/MIT dual license instead of just GPL.
<dt>1.3 (<time>2010-03-09</time>): </dt>
<dd>Detecting native support in Firefox 3.6; it had only been detecting support for 3.6 alpha, which
had significantly different syntax. I ported the linear gradient examples over to use the new native Firefox
syntax, but am still working on the radial gradients; the syntax has changed a lot!</dd>

<dt>1.2 (<time>2009-09-30</time>): </dt>
<dd>Phong Nguyen raised an <a href="http://weston.ruter.net/projects/css-gradients-via-canvas/#comment-9539"
title="This is pretty nice – except for one major issue I’ve seen. I’m
using the jQuery UI library and it includes a fairly large CSS file
(nearly 1700 lines!) that causes the forEach(document.styleSheets … )
loop to take a good long while to finish. This blocks the user from doing
anything to the page – in my case, for 2-3 seconds. That’s pretty
annoying for any user to have to deal with. Is there some way to speed up
that core loop? (Failing that, I could try and detect if I’m loading
certain large files and ignore them).">excellent point</a>
in that stylesheets which don't contain any CSS Gradients should be ignored in order
to improve performance (in his case, for example, the jQuery UI
stylesheets are large and don't need to be parsed).
Now you can add <code>class="no-css-gradients"</code> to any
<code>style</code> or <code>link</code> element and that will prevent
this script from looking for CSS Gradients to apply with canvas.</dd>

<dt>1.1 (<time>2009-08-12</time>): </dt>
<dd>Now if <code>cssGradientsViaCanvas.useCache</code> is set to
<code>true</code>, the CSS rules containing gradients are cached in
<code>sessionStorage</code> instead of having to be re-parsed out of
the stylesheets each time a page loads. For this to work, there
must be implementations of <code>JSON.stringify()</code> and
<code>JSON.parse()</code> available (e.g. <a

<dd>Ability to use
<code>data:</code> URIs for images is not explicitly detected since
testing for the presence of <code>canvas.toDataURI()</code> is

<dt>1.0.3 (<time>2009-08-10</time>): </dt>
<dd>Detecting support for native support for CSS Gradients in Firefox 3.6</dd>

<dt>1.0.2 (<time>2009-08-05</time>): </dt>
<dd>Now requiring that <code>gradient(…)</code> only be used with the
<code>background-image</code> property instead of with the
<code>background</code> shorthand properties since the
additional <code>background-*</code> properties are not parsed out.</dd>

(Since I started redirecting from my blog to GitHub, I've archived the old comments I had received there.)

Developed by Weston Ruter (@westonruter).