CSS3 → SVG Converter

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

  1. 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).
  2. 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.
  3. 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.
  4. Click the “Convert” button.
  5. 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.
  6. 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.

Next it takes the angle in degrees and converts it to radians.  CSS3 gradients rotate in degrees, but Javascript rotates in radians, so it needs to convert the value first.

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 Example
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).

CONTRIBUTE!

Octocat_smallDoes 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.

RELEASE NOTES

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:”)

  1. 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-.
  2. Optimized IE9 base64 output to retain original rgba/hsla/transparent colors, saving a few extra bytes per stop.
  3. Migrated all JS event handlers into the block to separate content and behavior.

Version 0.9

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:”

  1. Added full support for new unprefixed W3C syntax gradients (using ‘to <destination>’ syntax).
  2. 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.
  3. 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.
  4. If no directions or angle units are specified, the script will now assume defaults, as happens in CSS.
  5. “Angle units”? Yeah, there’s now support for all valid units, (deg, rad, grad, & turns). Plus negative values and decimals work.
  6. 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).
  7. Added support for RGB/A percents, HSL/A, floating points in RGB/A and HSL/A, color names, and ‘transparent’ keyword.
  8. Added logic to convert alpha values and ‘transparent’ to proper SVG ‘stop-opacity’ values.
  9. Overhauled the SVG vector generation logic, greatly improving accuracy.
  10. Added optional IE9 base64 output for CSS.
  11. 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.
  12. Extended SVG preview display/update capabilites to all capable browsers (Chrome 7+, IE9+, FF4+, Safari 5.1+, Opera 11.6+)

Known Issues:

  1. Still no radial-gradient support yet, but I plan to figure that out not too long from now!
  2. 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!
  3. 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!

ACKNOWLEDGEMENTS

I’m not very good with math so I would never have been able to figure out how to build this without the following:

http://stackoverflow.com/questions/5287954/how-to-calculate-svg-linear-gradient-attribute-x1-y1-x2-y2-if-we-know-angle

http://stackoverflow.com/questions/5027950/coordinates-for-my-javascript-game-based-on-an-angle-when-do-i-use-sin-cos-and

http://www.codeproject.com/KB/books/learnsvgchapter07.aspx

HUGE thanks to Anthony Martinez for his additions to this!  http://www.linkedin.com/in/canthonymartinez/

LICENSE

Free to use, modify, improve, distribute, or do whatever you want with it.  I’d appreciate a link back here or attribution though.

11 Comments

  1. How to convert below css into svg . I tried with your tool but I think it’s not working

    background-image: linear-gradient(135deg, rgba(255, 255, 255, .2) 25%, transparent 25%,transparent 50%, rgba(255, 255, 255, .2) 50%, rgba(255, 255, 255, .2) 75%,
    transparent 75%, transparent);

    • kmhcreative

      I need to revisit how it handles transparency. At the time I wrote this there were some problems across browsers regarding the display of SVG alpha channels. First of all my utility doesn’t understand what “transparent” means, but it also codes for SVG 1.1, which (to my understanding) does not support CSS-style rgba color declarations but requires using rgb color and a “fill-opacity” attribute instead. There was also a bug in webkit browsers (not sure if it has been fixed) that would display white instead of the transparency. I’ll try to get around to updating my utility, not sure when that will happen though.

  2. Anthony

    Hello there! I found your script when I was looking for some way to convert a bunch of gradients (about 250, ha) into SVG for IE9. I kept getting inaccurate renderings, however, particularly with non-square SVG dimensions. So, I ended up taking some time to dive into the script’s internals and make a bunch of updates to it. Check out my JSFiddle and let me know what you think! For starters, all of the ancient Webkit syntax should work correctly now, including stops in decimal form, and stops in the form of from() and to(). Plus, there’s now HSL and HSLA support, and proper transparency support. That’s only a few of the changes!

    • kmhcreative

      Thank you, thank you, Anthony for all your work updating and expanding this little project!

      It’s been one of those things I kept meaning to get back to, but other priorities got in the way. But that’s the great thing about releasing code anyone can play with, there’s stuff in your revision I’d never even have thought to address. I’ve updated the version at the link in the article above to your 0.9, and of course anyone else who wants to take a shot at advancing it can check out your JSFiddle. 🙂

      • Anthony

        You’re welcome! I’m glad I could help 🙂

        I’ve published a 0.9.5 update that includes what I think is a killer feature, a batch mode! With it, I was able to produce my 250 or so SVG gradients I needed, almost instantly. Finally! That was the moment I was working toward 🙂 Check out the latest tweaks at my updated JSFiddle.

        Since I added another checkbox for the “Batch Mode”, I decided to streamline a bit and convert the clear on focus or manual radio buttons to just one checkbox, left unchecked by default. I also added a little text on the bottom to solicit bug reports / feedback to either my JSFiddle or email address. I don’t know if you want to include that on your live page, but it’s there. Eventually, (once I get more organized with my online life, ha), I plan to feature the SVG generator with my script updates on my personal web site, if that’s okay? Of course, I’d make sure to keep the attribution to you.

        Finally, one last little thing to point out–on your live page for the generator, the doctype is messed up; it’s spelled as “DOCTYTPE” instead of “DOCTYPE”, and that does affect the page rendering slightly 🙂

        Well, if you have any suggestions for further script tweaks/additions, just let me know! Although, I can’t promise I’ll get around to any more updates soon, for I have a ton of other stuff now I need to catch up on now.

        • kmhcreative

          Anthony, thank you for the heads-up on the DOCTYPE (darned stumbling fingers!). Fixed! As noted in the updated project page above I’m pointing people to your JSFiddle and I also set up an actual GitHub repository (my first!). I figure between your JSFiddle and the GitHub repo it should be pretty easy for any others who are interested to contribute and improve this project. Thanks again for all your great work!

  3. Anthony

    You’re welcome! Don’t you just hate stumbling fingers? Coding can be such a pain sometimes 😛 Anyway, I saw the Github repo–great! Would it be possible for me to become a contributor on it? Or should I just create my own fork?

    I find JSFiddle a little clumsy for handling updates, since the URL has to be changed each time (maybe that’s my fault for creating the fiddle without an account? I don’t know, haha. I’m still kinda new to JSFiddle anyway.) I’d also like to touch up the repo documentation, such as making sure all references to me are in third-person (it’s not my repo! 🙂 ), and updating (possibly removing?) some statements that reflect the 0.1 version. For example, I now have the auto-clearing feature turned off by default, while the documentation assumes it’s on by default. Stuff like that. I’d also like to add a little roadmap of future updates. Like, I’d possibly like to include Canvas export for 1.X (which could then be converted to PNG / base64 PNG for browsers that don’t support SVG…like….*cough*, IE8- *cough*, haha. Radial gradients, I may plan for 2.X…etc.

    I have a 0.9.6 update live now, with a few improvements / bug fixes. For example, IE9- now has support for the base64 output and Batch Mode. I do believe that’ll be my last update for a while…or who knows, I may stumble into a new bug tomorrow! 😛

    • kmhcreative

      I’m brand new to GitHub, but what I do know is they use the word “fork” in a way that means something else to a lot of people. As soon as you click the “Edit” button when viewing the code in your browser it will automatically “fork” it, and as it is a “public” project you just need to be registered and signed in to edit/fork any of the files in the project. You should only need to do the “cloning,” “pull request” and “push” stuff if you want to work on a local/offline version first and then commit changes. At least that’s my understanding, I’ve never contributed to anything on git before today.

      • Anthony

        Thanks for the latest comment. I’ll look into learning more about working with Github soon!

        I’ve gone ahead and registered css3tosvg.com, because I’d like to make my own (and first) “one-page web app” with the updated script and customized CSS/appearance. This would be something to include on my resume/portfolio. Of course, I’d keep a link and attribution to you since you came up with the original code, as well as keep links to the JSFiddle and Github repo. What do you think? Do you have any objection to my use of the domain? I don’t want to run afoul of any copyright 🙂

        • kmhcreative

          If all you want to do is edit the code via your web browser GitHub is easy for that. Sign in, click the “Edit” button, add notes about what you did, commit the changes. Done! Normally “fork” means you are creating a new “branch” and taking the code in a different direction. However of GitHub “fork” is closer in meaning to “file check-out” and taking the code in another direction is done by creating new “branches” through a separate process.

          While I didn’t release it under any specific license I did say “Free To Use & Distribute” and only suggested attribution would be nice and appreciated so I guess the closest Creative Commons license would be “Attribution-ShareAlike 3.0 Unported” (http://creativecommons.org/licenses/by-sa/3.0/) and so far as the attribution goes as long as the original project credit is in the code itself I’m cool with that. But I put it out there for others to use, improve, and share so go for it!

          • Anthony

            Perfect! Thanks for the permission. I’ll hopefully have something up on my domain in the coming days to next few weeks, and I’ll definitely adhere to that Creative Commons license.

            In the meantime, I think I’m getting the hang of Github! I already submitted two pull requests on the repo for your consideration. I’m officially a Githubber now 🙂 I’ll likely have a few more little edits to make shortly, since I’m going to re-create my JSFiddle while logged in to my JSFiddle account (I originally made it anonymously). That should hopefully allow me to make updates to the fiddle without having to increment the URL every time.

Leave a Reply


Menu




Search

Posts

About

Comment11

Contact

Share

Share this On:

Google+ Reddit Stumble It Digg this! LinkedIn Pinterest RSS Feed E-mail Link!