Question

I have been exploring using SVG's for the latest website I've been building - bit behind the times so trying to catch up. I initially setup my file similar to the way I would do a normal sprite. Although this worked, it does seem a little clumsy when you want to take advantage of resizing the vector and then trying to find the new background position in the document!

After doing some research I came across the idea of stacking it via layers - which makes a heap of sense. After getting all excited and successfully doing this I then came across a few posts saying this isn't support in all browsers - typical.

https://code.google.com/p/chromium/issues/detail?id=128055#c6

Here is a great tutorial for stacking SVG images in a single file as well as some work arounds for browsers that don't support it: http://hofmannsven.com/2013/laboratory/svg-stacking/

Although this works fine, is there an alternative to save writing all this extra code and fallbacks?

Was it helpful?

Solution

After thinking about this a little I decided I could take advantage of the Apache server and see if I could simply inject what I needed into the document. The end result? Works perfect in all browsers :)

To start with I added some code in my .htaccess file to capture all .svg requests

RewriteRule ^(.*)\.svg$ /{path-to-file}/svg.php [L]

Then I wrote a few lines to deal with the target layer and inject that into the file

(UPDATE) Added new variable called target-fill to allow for dynamically changing the fill colour of a shape if required

<?php
// Set the SVG header
header('Content-Type: image/svg+xml');
$queryString = Array();
if(isset($_SERVER['QUERY_STRING'])) $queryString = explode('&', $_SERVER['QUERY_STRING']);
// Get target from the query string
$target = $queryString[0];
    // Get a fill alternative if available and valid
if(isset($queryString[1]) && hexdec($queryString[1]) !== false) {
    $targetFill = '#' . $queryString[1];
} else {
    $targetFill = '';
}
// Validate the target - this is your ID in the SVG file
$validTargets = Array('Camera', 'Layer_1');
if(!in_array($target, $validTargets)) $target = false;
// Get contents of the file - tweak this depending on where you have saved this file to relative to the root of your website
$filename = '../..' . $_SERVER['REDIRECT_URL'];
// Get the contents of the file
$contents = file_get_contents($filename);
// Replace the target with the valid target above
// - doing it this way rather than echoing the target in the SVG file as it seemed like a security risk
if($target) $contents = str_replace('g:target', 'g#' . $target, $contents);
// Replace the fill colour if available
$contents = str_replace('target-fill', $targetFill, $contents);
// Output the amended SVG file
echo $contents;

Included near the top of the SVG is the stacking code to hide we don't want displayed and to turn on what we do

<defs>
    <style>
      svg g { display: none }
      svg g:target, svg g:target g { display: inline }
      svg g:target * { fill: target-fill; }
    </style>
</defs>

And that is it. So now instead of calling your SVG file like (also works as a background image):

<img src="images/svg-file.svg#Camera">

You would do it like this

<img src="images/svg-file.svg?Camera">

The advantage of doing it this way is you can now also do some further checks based on the user agent to return an alternative file altogether if SVG isn't supported.

(UPDATE) You can now also express a second parameter to change the fill colour if required. Use it like this:

<img src="images/svg-file.svg?Camera&cc0000">

Hope this helps someone else out there.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top