7

I have a complex Jquery-UI based dialog and I want to provide a SVG image as background. I tried to make this work in a simple test file first and it does not work though the SVG, as a standalone image, works fine. Here is the simplified code:

 <script>
 $(document).ready(function () { 
  svg = "<svg width='400' height='400' fill='url(#grad1)'  \
   xmlns='http://www.w3.org/2000/svg'> <rect id='bkgrect' width='400' \
   height='400' style='fill:'url(#grad1)'; stroke-width:3;'/> <defs>\
   <linearGradient id='grad1' x1='0' y1='20%' x2='0%' y2='100%'> \
   <stop id='stop1' offset='0%' stop-color='blue'/> <stop offset='100%' \
   stop-color='white'/> </linearGradient> </defs> </svg>";
  svgBase64 = btoa(svg);
  bkgrndImg = "url('data:image/svg+xml;base64,"+ svgBase64  +"')";
  $('#testDiv').css('background-image', bkgrndImg);
 });
</script>
</head>
<body>
  <div id='testDiv' style="border:2px solid red;width:400px;height:400px;
     position:absolute;left:100px;top:100px;"> Some SVG Div </div>
  <svg ... /svg>

The svg ... /svg is the same svg as used in the background and it displays properly.

After looking at various solutions, I have relied primarily on this post. I also tried to simulate background SVG image by using z-index and positioning the image in the Div as an image but thats not a good fix. I want to get SVG as a background image to work smoothly across browsers because at least SVG gradients are well supported in all modern browsers and I think the time for SVG's potential to be fully realized has finally arrived.

Community
  • 1
  • 1
Sunny
  • 9,245
  • 10
  • 49
  • 79
  • 2
    Do you have to have it as base64? Could you not just externally link to the svg like a normal image? `background: url(../images/fancy.svg)` If the svg is not dynamic I find it easier to maintain as a normal file. – Lex Jan 05 '16 at 13:46
  • 1
    @Lex I want to have it inline so I can change it dynamically with JS. – Sunny Jan 05 '16 at 13:48
  • the post you have mentioned is asking to escape # which you did not do as I see # replaced with %23. – wui Jan 05 '16 at 13:53
  • @koded I am using the answer provided by Mike Tommasi though it is not the accepted answer in that post. I found that answer to be more natural. – Sunny Jan 05 '16 at 13:55
  • PLEASE SEE MY COMMENTS TO THE ACCEPTED ANSWER. THEY MAY BE HELPFUL... – Sunny Jan 06 '16 at 04:01

3 Answers3

3

Here is an alternative. You could use CSS classes then in your Javascript just change its class to toggle between different backgrounds. See example below:

$('button').click(function() {
  $('#testDiv').toggleClass('gradient1 gradient2');
});
  .gradient1 {
    background: #4e8ef7 url(data:image/svg+xml;base64,Cjxzdmcgd2lkdGg9IjUwMHB4IiBoZWlnaHQ9IjUwMHB4IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogPGRlZnM+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkaWVudCIgeDE9IjAuNSIgeTE9IjAiIHgyPSIwLjUiIHkyPSIxIj4KICAgPHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjMjk2YWQ0IiAvPgogICA8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiM0ZThlZjciIC8+CiAgPC9saW5lYXJHcmFkaWVudD4KIDwvZGVmcz4KIDxnPgogIDxyZWN0IGZpbGw9InVybCgjZ3JhZGllbnQpIiBzdHJva2Utd2lkdGg9IjAiIHg9IjAiIHk9IjAiIHdpZHRoPSI1MDAiIGhlaWdodD0iNTAwIiAvPgogPC9nPgo8L3N2Zz4KICAgIA==) top repeat-x;
    background-size: contain;
  }
  .gradient2 {
    background: #7962ff url(data:image/svg+xml;base64,Cjxzdmcgd2lkdGg9IjUwMHB4IiBoZWlnaHQ9IjUwMHB4IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogPGRlZnM+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkaWVudCIgeDE9IjAuNSIgeTE9IjAiIHgyPSIwLjUiIHkyPSIxIj4KICAgPHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjM2ZiYWUyIiAvPgogICA8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiM3OTYyZmYiIC8+CiAgPC9saW5lYXJHcmFkaWVudD4KIDwvZGVmcz4KIDxnPgogIDxyZWN0IGZpbGw9InVybCgjZ3JhZGllbnQpIiBzdHJva2Utd2lkdGg9IjAiIHg9IjAiIHk9IjAiIHdpZHRoPSI1MDAiIGhlaWdodD0iNTAwIiAvPgogPC9nPgo8L3N2Zz4KICAgIA==) top repeat-x;
    background-size: contain;
  }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Change gradient</button>

<div class="gradient1" id='testDiv' style="border:2px solid red;width:400px;height:400px;
     position:absolute;left:100px;top:100px;">Some SVG Div</div>

Or

$('button').click(function() {
  var mySVG = "<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10'><linearGradient id='gradient'><stop offset='10%' stop-color='#EEE'/><stop offset='90%' stop-color='#fcc'/> </linearGradient><rect fill='url(#gradient)' x='0' y='0' width='100%' height='100%'/></svg>";
  var mySVG64 = window.btoa(mySVG);
  document.getElementById('testDiv').style.backgroundImage = "url('data:image/svg+xml;base64," + mySVG64 + "')";
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Change gradient</button>

<div class="gradient1" id='testDiv' style="border:2px solid red;width:400px;height:400px;
     position:absolute;left:100px;top:100px;">Some SVG Div</div>

EDIT Added OPs gradient color.

Problem is with syntax :

Change style='fill:'url(#grad1)'; stroke-width:3;' to style='fill:url(#grad1);stroke-width:3;' -- remove the ' around the url() and it should work

$(document).ready(function() {


  var mySVG = "<svg xmlns='http://www.w3.org/2000/svg' width='400' height='400' fill='url(#grad1)'><rect id='bkgrect' width='400'    height='400' style='fill:url(#grad1);stroke-width:3;' /><linearGradient id='grad1' x1='0' y1='20%' x2='0%' y2='100%'><stop offset='0%' stop-color='blue'/><stop offset='100%' stop-color='white'/> </linearGradient><rect fill='url(#grad1)' x='0' y='0' width='100%' height='100%'/></svg>";


  var mySVG64 = window.btoa(mySVG);
  document.getElementById('testDiv').style.backgroundImage = "url('data:image/svg+xml;base64," + mySVG64 + "')";


});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='testDiv' style="border:2px solid red;width:400px;height:400px;
     position:absolute;left:100px;top:100px;">Some SVG Div</div>

Read more here about styling properties

Raja Khoury
  • 3,015
  • 1
  • 20
  • 19
  • this is pretty much the answer that is accepted in the [post]( http://stackoverflow.com/questions/10768451/inline-svg-in-css) referenced by me, although you have added some Jquery to it. My problem is that it works with the SVG image there, which is the one used by you too, but not with my SVG. I would like to know why it does not work with my SVG, which SVG works fine, stand-alone but not as a background. I am upvoting the answer because you certainly have taken some efforts... Thanks – Sunny Jan 05 '16 at 14:43
  • @Sam I updated my answer. The issue is with your JavaScript syntax. – Raja Khoury Jan 05 '16 at 19:23
  • Though I have accepted the above answer because it identified the typo which failed my SVG, my solution to this problem is more generic. When trying to apply SVG as background, one has to scale the background gradient. The spreadMethod options do not help. I built a simple function which takes the DIV id and the gradient parameters to do this. It then fetches the width/height of the DIV, builds the SVG and applies it to the backgroundImage css. This is 100% full proof with respect to scaling of the background. The "S" in SVG does not apply to all situations. – Sunny Jan 06 '16 at 04:00
  • The above solution is more intended for cross-browser solution... Simple – Sunny Jan 06 '16 at 04:21
2

You could try not using the base64 encoding, as described here:

https://css-tricks.com/probably-dont-base64-svg/

.bg {
  background: url('data:image/svg+xml;utf8,<svg ...> ... </svg>');
}

However, if you only want the gradient, you could just use the CSS background-image: linear-gradient(blue, white) syntax.

KWeiss
  • 2,954
  • 3
  • 21
  • 37
  • It is the accepted answer in the post referred by me. I tried it but it does not work. Its rather old post. It also talks about SVG content to be URL-escaped. I will take a closer look at the reference provided by you. – Sunny Jan 05 '16 at 14:04
  • 1
    I tried again with and without the SVG content to be URL-escaped. I found that the example provided for a similar accepted answer in the post referenced by me does work but fails for my SVG. – Sunny Jan 05 '16 at 14:26
  • is it correct to say that pure SVG (without libraries like Rafael) gradients are more browser-supported then CSS background-image, linear-gradient? – Sunny Jan 05 '16 at 14:52
  • 1
    SVG is slightly better supported, but a bit less predictable. SVG Support: http://caniuse.com/#feat=svg, gradient support: http://caniuse.com/#search=linear-gradient, more info: https://css-tricks.com/using-svg/. I tried to find out why your SVG specifically does not work, I'd assume some characters need to be escaped. I'll get back to you if I find out which ones. – KWeiss Jan 05 '16 at 15:06
1

It doesn't work because you're missing xmlns:xlink="http://www.w3.org/1999/xlink" on the root <svg> element.

I tried running mine as a standalone .svg file and got the error Namespace prefix xlink for href on ... is not defined, which led me to this question.

Nadroev
  • 363
  • 1
  • 11