CSS3 gradients are a pretty neat way to dress up a web page, but older browsers can’t display them. Also, in Internet Explorer 9 is you have a gradient background in a box with rounded corners the gradient won’t be clipped by those rounded corners (the gradient sticks out square instead of being rounded off). The only solution for older browsers and the IE9 gradient clipping issue is to use a fallback image for the background.
What I wanted was an easy way to convert my CSS3 gradients into images as a fallback that would still maintain the appearance I had so carefully crafted. The obvious best choice was to use SVG (Scaleable Vector Graphics), for which support is getting better but there will still be browsers that can’t display it (or can’t do so without a plugin). However, once you have the SVG image you can open it a graphics editor (Illustrator, Photoshop, Inkscape, or GIMP) and convert it to a JPG for even broader fallback support. I looked and looked for such a converter – figuring someone somewhere must have already made one – but couldn’t find one. So I ended up writing one myself:
>> Stable Version 0.9.5 <<
I put all the code in one page so you can either just use it from the link above or you can go there and save the page to your computer and run it locally.
HOW TO USE IT
- Copy and paste almost any CSS3 Linear Gradient code into the input box at the top of the utility page. It will accept W3C standards or Mozilla, Webkit (both old and new syntax), Opera, and Microsoft proprietary “vendor” versions (see the “Release Notes” at the end of this page for details).
- If you are converting a lot of gradients to SVGs then you’ll probably want to leave it so it automatically clears the input box each time you click in it to paste in a new string. However, if you want to “play around” with the variables in the CSS code and see what changes you can turn off the auto-clearing feature.
- Set a size for your SVG image. Typically for tiled background images it is best to leave this at “percent” because it will automatically stretch and compress to fill the background of the element. On the other hand if you know the gradient will fill the background of an element with a specific size you can set it in pixels instead.
- Click the “Convert” button.
- The source code for your SVG file appears in the output box. Copy and paste it into any plain text editor and save it with the file extension “.svg” and you’ll have your SVG image file.
- The “Preview” takes the same information in the source code and builds an actual SVG file into the page for you to see exactly how it will look. Obviously your browser needs to support SVG images for this to work!
Note to Firefox users: Your browser allows you to edit the source code and press the “Update” button and see a live update in the preview of your changes.
HOW IT WORKS
First it parses the CSS gradient string into the component parts. If the string uses words (such as top, top left, bottom, bottom left, left, right) to indicate rotation rather than degrees (i.e., 45deg) then it first normalizes the verbose parameters to their degree value equivalents.
Once it has radians it then converts the result into vector coordinates. SVG can rotate either in degrees or with vector coordinates. You may be wondering why I didn’t just preserver the CSS degrees and use it for the SVG? Well, it doesn’t give you exactly the same results as the vector coordinates. With vector coordinates you can make sure the gradient properly fills the space. SVG gradient rotation (with the gradientTransform=rotate(n) attribute) doesn’t change the length of the vectors. However, another problem I discovered was that certain angles didn’t map properly using the SVG rotate attribute! It was most noticeable with 315 degrees and its mirror 135 degrees, but the problem affected all degrees within each of those quadrants of the circle. The rotate attribute offers no real options to correct this so I had to get the vector coordinate method to work.
Initially I thought the script was wrong because I reasoned a 45 degree angle should have vector coordinates like this: x1=”0%” y1=”100%” x2=”100%” y2=”0%” but my script was producing this: x1=”0%” y1=”70%” x2=”70%” y2=”0%”
Oddly enough at a small scale this still looks like a proper 45 degree angle. So does its mirror of 225 degrees. But when I made the CSS gradient fill the browser it became apparent that even in CSS3 gradients a 45 degree angle doesn’t actually hit at the corners of a square – it’s slightly offset just like the SVG images.
But the vector coordinates suffered the same problem as the rotation attribute in that 135 degrees, 315 degrees, and all the other degrees within their quadrants were offset from where they should be. Here’s an example of what I’m talking about:
|CSS3 Gradient 135deg||SVG rotation(135)||SVG with fix applied|
CSS3 Gradient: background: -webkit-linear-gradient(135deg, #779ae8 0%,#376fe0 50%,#2260dd 51%,#3690f0 51%,#2463de 100%);
SVG Rotation: <linearGradient id=”grad” gradientTransform=”rotate(135)” > or SVG Vector: <linearGradient id=”grad” x1=”70%” y1=”70%” x2=”0%” y2=”0%”>
After about a day of trying to figure out why this was happening I finally just settled on a hack to correct it. The offset in both quadrants was consistent so in my checks for negative numbers I simply told it if it was a positive value for a degree setting that fell in between 90 and 180 degrees or between 270 and 360 to add .3 to the radians value before converting to vector coordinate percentages, which effectively turns each “70%” in the examples above to “100%.” As you can see from the images above it fixes the problem perfectly, though I’m still not clear why it happens in the first place at least my converter now makes SVG image consistent with the CSS3 input.
The next thing the converter does it wraps all the parameters in the XML code needed to create the SVG source code. Lastly it creates a SVG element in the page with the same parameters for the Preview.
For Firefox users there’s an additional function because that browser supports creating the SVG preview image from the code in the output box – meaning you can edit that code in the output box, click “Update” and see your changes immediately reflected in the preview. Unfortunately this isn’t supported by any of the other browsers. (See below, v0.9 supports more browsers).
Does the “CSS3 → SVG Converter” not do some cool thing you want it to do? If you’ve got the skills and want to help expand, update, or fix stuff in the converter you can play around with it at the JSFiddle set up by Anthony Martinez: http://jsfiddle.net/CG9t2/1/ and/or commit your changes to the project, which now has an official repository at GitHub: https://github.com/kmhcreative/css2svg.
Version 0.9.5 (May 27, 2013)
Overview of major changes, done by Anthony Martinez (http://www.linkedin.com/in/canthonymartinez/). (All other script/CSS Annotations by me are preceded by “AM:”)
- Added an optional batch mode to generate base64 CSS output for multiple selectors at once. Yes! Another exclusive feature, as far as I know. Born out of frustration with the limitations of existing LESS mixins and online gradient generators, this blows everything out of the water 🙂 Requires IE10 or any recent release of Chrome, FF, Safari, or Opera; it won’t work in IE9-.
- Optimized IE9 base64 output to retain original rgba/hsla/transparent colors, saving a few extra bytes per stop.
- Migrated all JS event handlers into the block to separate content and behavior.
Overview of major changes, done by Anthony Martinez (http://www.linkedin.com/in/canthonymartinez/). All other script/CSS Annotations by him are preceded by “AM:”
- Added full support for new unprefixed W3C syntax gradients (using ‘to <destination>’ syntax).
- Added logic to calculate degrees differently, to match the new W3C syntax.For example, try -moz-linear-gradient(72deg,#fff,#000) and linear-gradient(72deg,#fff,#000) in CSS — they render differently.Then input them into this script, and they should each render in SVG the same way they do in CSS.
- If all color stop percentages are missing, then the script will now interpolate them, as happens in CSS.If only the start and ending stops are missing, the script will add them.
- If no directions or angle units are specified, the script will now assume defaults, as happens in CSS.
- “Angle units”? Yeah, there’s now support for all valid units, (deg, rad, grad, & turns). Plus negative values and decimals work.
- Improved support for old Webkit syntax — from() and to() will work as expected, even with decimals, and even if to() comes before other color-stops (as is acceptable).
- Added support for RGB/A percents, HSL/A, floating points in RGB/A and HSL/A, color names, and ‘transparent’ keyword.
- Added logic to convert alpha values and ‘transparent’ to proper SVG ‘stop-opacity’ values.
- Overhauled the SVG vector generation logic, greatly improving accuracy.
- Added optional IE9 base64 output for CSS.
- Added multiple background support. Yes! No other SVG or gradient generator I’m aware of, even the awesome visualcsstools.com that I drew inspiration from, has this.
- Extended SVG preview display/update capabilites to all capable browsers (Chrome 7+, IE9+, FF4+, Safari 5.1+, Opera 11.6+)
- Still no radial-gradient support yet, but I plan to figure that out not too long from now!
- For some reason, FF3.6 and below can only do one conversion per page load/refresh. Those browsers are ancient, though. So, perhaps they’re not worth trying to fix? It’s odd, though. Even IE7 works the script flawlessly!
- Older browsers that don’t fully support RGBA or HSL/A will trip on the color validation loop I included, if input gradient(s) has/have RGBA and/or HSL/A.
Version 0.1 (Archived)
Preview does not work in Internet Explorer, however the source code output does so you can still make SVG images with it.
CSS3 Gradient parameters that are NOT supported:
- color stops expressed as decimals (ex. “0.7”) instead of percentages (ex. “70%”)
- The old webkit “from” and “to” syntax is not supported. So this will not work:
-webkit-gradient(linear, 0% 0%, 0% 100%, from(#666666), to(#666666), color-stop(.6,#333))
However, the old syntax in this format IS supported:
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#666666), color-stop(100%,#666666), color-stop(60%,#333333));
- No support for “hsl” or “hsla” color stops. Only “hex,” “rgb” and “rgba” are supported. However “rgba” (alpha channel) support varies across browsers so you will probably want to change them to “rgb” instead for better compatibility.
- The converter currently does not support “radial” gradients at all!
I’m not very good with math so I would never have been able to figure out how to build this without the following:
HUGE thanks to Anthony Martinez for his additions to this! http://www.linkedin.com/in/canthonymartinez/
Free to use, modify, improve, distribute, or do whatever you want with it. I’d appreciate a link back here or attribution though.