Base64 encoded SVG gradient backgrounds in LESS
So, CSS3 gradients are cool. Sure, you need to use a couple of different vendor prefixes but the syntax is pretty nice
.my-gradient { background: -moz-linear-gradient(top, #00b7ea 0%, #009ec3 100%); /* FF3.6+ */ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#00b7ea), color-stop(100%,#009ec3)); /* Chrome,Safari4+ */ background: -webkit-linear-gradient(top, #00b7ea 0%,#009ec3 100%); /* Chrome10+,Safari5.1+ */ background: -o-linear-gradient(top, #00b7ea 0%,#009ec3 100%); /* Opera 11.10+ */ background: -ms-linear-gradient(top, #00b7ea 0%,#009ec3 100%); /* IE10+ */ background: linear-gradient(to bottom, #00b7ea 0%,#009ec3 100%); /* W3C */ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00b7ea', endColorstr='#009ec3',GradientType=0 ); /* IE6-8 */} |
The only caveat here is the filter declaration for IE. You’re limited to a straight top-to-bottom linear gradient (no multi-stops) but more importantly, the gradient background will overflow any border radius you may have defined.
No problem, IEs 7 and 8 don’t support border-radius anyway but what about IE9? The solution…
SVG background images
The standard SVG gradient background definition looks something like this
<?xml version="1.0" ?> <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none"> <linearGradient id="grad-ucgg-generated" gradientUnits="userSpaceOnUse" x1="0%" y1="0%" x2="0%" y2="100%"> <stop offset="0%" stop-color="#00b7ea" stop-opacity="1"/> <stop offset="100%" stop-color="#009ec3" stop-opacity="1"/> </linearGradient> <rect x="0" y="0" width="1" height="1" fill="url(#grad-ucgg-generated)" /> </svg> |
You can then base64 encode this and set it as a data URI background image which will work beautifully in IE9. For example
background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2l...); |
Doing it with LESS
I’ve been using LESS lately and was almost going to move to SASS + Compass in order to achieve the above but found a way to stick with LESS. Enter the base64DataUriBackground mixin. This can be made very simple if your LESS parsing environment has access to the btoa() function.
.base64DataUriBackground (@encode, @type: ~"image/svg+xml") { @dataUriPrefix: ~"url(data:@{type};base64,"; @dataUriSuffix: ~")"; // with btoa() @b64DataUri: ~`(function(a,b,c){return a+btoa(b)+c})('@{dataUriPrefix}','@{encode}','@{dataUriSuffix}')`; // without @b64DataUri: ~`(function(a,b,c){function e(a){a=a.replace(/\r\n/g,'\n');var b='';for(var c=0;c<a.length;c++){var d=a.charCodeAt(c);if(d<128){b+=String.fromCharCode(d)}else if(d>127&&d<2048){b+=String.fromCharCode(d>>6|192);b+=String.fromCharCode(d&63|128)}else{b+=String.fromCharCode(d>>12|224);b+=String.fromCharCode(d>>6&63|128);b+=String.fromCharCode(d&63|128)}}return b}function f(a){var b='';var c,f,g,h,i,j,l;var m=0;a=e(a);while(m<a.length){c=a.charCodeAt(m++);f=a.charCodeAt(m++);g=a.charCodeAt(m++);h=c>>2;i=(c&3)<<4|f>>4;j=(f&15)<<2|g>>6;l=g&63;if(isNaN(f)){j=l=64}else if(isNaN(g)){l=64}b=b+d.charAt(h)+d.charAt(i)+d.charAt(j)+d.charAt(l)}return b}var d='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';return a+f(b)+c})('@{dataUriPrefix}','@{encode}','@{dataUriSuffix}')`; background: @b64DataUri; } |
Here’s an example gradient mixin
.gradient (@gradient-top, @gradient-bottom) { @svg: ~'<?xml version="1.0" ?><svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none"><linearGradient id="grad-ucgg-generated" gradientUnits="userSpaceOnUse" x1="0%" y1="0%" x2="0%" y2="100%"><stop offset="0%" stop-color="@{gradient-top}" stop-opacity="1"/><stop offset="100%" stop-color="@{gradient-bottom}" stop-opacity="1"/></linearGradient><rect x="0" y="0" width="1" height="1" fill="url(#grad-ucgg-generated)" /></svg>'; .base64DataUriBackground(@svg); background: -moz-linear-gradient(top, @gradient-top 0%, @gradient-bottom 100%); /* FF3.6+ */ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,@gradient-top), color-stop(100%,@gradient-bottom)); /* Chrome,Safari4+ */ background: -webkit-linear-gradient(top, @gradient-top 0%,@gradient-bottom 100%); /* Chrome10+,Safari5.1+ */ background: -o-linear-gradient(top, @gradient-top 0%,@gradient-bottom 100%); /* Opera 11.10+ */ background: -ms-linear-gradient(top, @gradient-top 0%,@gradient-bottom 100%); /* IE10+ */ background: linear-gradient(to bottom, @gradient-top 0%,@gradient-bottom 100%); /* W3C */ filter: ~"progid:DXImageTransform.Microsoft.gradient( startColorstr='@{gradient-top}', endColorstr='@{gradient-bottom}',GradientType=0 )"; /* IE6-8 */ } |
One final thing you will need to do is disable the filter declaration for IE9 (and above). You can achieve this simply through a conditional stylesheet
<!--[if gte IE 9]>
<style type="text/css">.my-gradient-class{filter: none;}</style>
<![endif]--> |
All CSS examples courtesy of the most awesome Ultimate CSS Gradient Generator.




