Write an equivalent <svg> for a <image xlink:href="something.svg" /> - dictionary

Feel free to ask for more context if you're wondering why this is necessary, or want to suggest a better way to solve the bigger problem. (It involves laying out a bunch of building floor plans onto a campus map and finding the absolute location of certain things that are in those building maps; more detail was bogging the question down.)
The short version is that I want to take an SVG file that has <image xlink:href="something.svg" /> references and merge it into one big file with each referenced SVG being embedded with an <svg> and inline SVG XML content.
So, my top-level source file (composed in Inkscape) looks like this:
<image xlink:href="floorplans/bldg1.svg"
width="165.52684" height="107.10559" y="-1937.7657"
x="2507.1565" transform="matrix(0,1,-1,0,0,0)" />
And my attempt at a merged version to inline all the vector data:
<svg x="2507.1565" y="-1937.7657" width="165.52684" height="107.10559"
transform="matrix(0,1,-1,0,0,0)" viewBox="0 0 1224 792">
<g id="surface0">
<path style="fill:none;stroke-width:0.72;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);...
So, basically I'm using a script to replace <image> with <svg> and paste in the contents of the root <svg> of "floorplans/bldg1.svg". (Copying attributes from the <image> to the <svg>, and copying the viewBox attribute from the original <svg> to the new one.)
This technique worked for things that aren't rotated, but Chrome seems to be saying this particular element is off the top of the viewport. I'm new to SVG, but I'm thinking the order of the transformations isn't the same on the <svg> as it is on the <image>. Did I make a dumb mistake I'm not spotting, or is there more involved in converting an <image xlink:href="something.svg" transform=... /> to an <svg> with inline XML?
Thanks.

The transform attribute doesn't apply to the <svg> element according to the SVG specification. You can put the transform that was on the <image> element on the <g> element either outside or inside the <svg> instead.
The reason for transform behaving this way is that the <svg> element sets up the coordinate system, and the transform depends on that (a question that would arise if it did apply is "should the transform be interpreted in the coordinate-space before or after the svg coordinate system is setup?")

Related

Import an SVG element from another document, without losing the CSS <style> from the original file

I need to create a number of SVG files and would love to keep a set of common symbols in one file and import them into the others.
I managed to do this using a <use> element:
<use href="common.svg#symbol1" />
The problem is that if common.svg has a CSS style that affects an element, the style has no effect in the file where the element is imported.
I uploaded two SVGs on svgur.com to show this:
https://svgur.com/i/bYv.svg
...defines a circle with id ball affected by a style that sets a red border around it.
<svg width="100" height="100" version="1.1" xmlns="http://www.w3.org/2000/svg">
<style>#ball { stroke:#ff0000; stroke-width:10; }</style>
<circle id="ball" cx="50" cy="50" r="45" />
</svg>
https://svgur.com/i/bXA.svg
...uses the circle. The circle is visible but the border is not.
<svg width="100" height="100" version="1.1" xmlns="http://www.w3.org/2000/svg">
<use href="bYv.svg#ball" />
</svg>
Questions:
Is this a bug of the SVG renderer I'm using or is it how it's supposed to behave?
Every renderer I tried (chrome, firefox, inkscape) shows the same result so I suspect this might be the intended behavior.
Is there any way to import an element from an external SVG file and the CSS styles that affect it too, so that it appears exactly like it does in its original document?
Is this a bug of the SVG renderer I'm using or is it how it's supposed to behave?
It is the intended behaviour. CSS rules do not apply across document boundaries. You are importing the SVG into your main document, but your CSS is in another document.
Is there any way to import an element from an external SVG file and the CSS styles that affect it too...
No.
Well I suppose you could technically write some Javascript to load the other file and extract the CSS rules. But I strongly suspect you don't want to do that.
You SVG "sprite document" should not have CSS rules in a <style> tag.
The best approach is to pre-prepare you SVGs to be used as sprites.
What I would do is import your common.svg into a vector editor and convert all your CSS attributes into presentation attributes. For example Illustrator lets you choose the method of styling when you export an SVG.
What you want is for something like this:
<svg>
<style>
.st0 {
fill: red;
}
</style>
<symbol id="whatever">
<path d="..." class="st0"/>
</symbol>
</svg>
to be converted to:
<svg>
<symbol id="whatever">
<path d="..." fill="red"/>
</symbol>
</svg>
According to the Scalable Vector Graphics (SVG) 2
specification (W3C Editor’s Draft, 08 June 2021) it seems that the style of the original document should be applied where an element is imported.
Section 5.5. The ‘use’ element:
The cloned content inherits styles from the ‘use’ element and can be the target of user events. However, these cloned element instances remain linked to the referenced source and reflect DOM mutations in the original. In addition, all style rules that apply in the scope of the referenced element also apply in the scope of the cloned shadow tree.
And 5.5.3. Style Scoping and Inheritance:
The use-element shadow tree, like other shadow trees, exhibits style encapsulation, as defined in the CSS Scoping module [css-scoping-1]. This means that elements in the shadow tree inherit styles from its host ‘use’ element, but that style rules defined in the outer document do not match the elements in the shadow tree. Instead, the shadow tree maintains its own list of stylesheets, whose CSS rules are matched against elements in the shadow tree.
When the referenced element is from an external document, the stylesheet objects generated when processing that document apply to the shadow tree, and are read-only. All URL references in the stylesheet, including fragment-only references, must be made absolute, relative to the URL of the document that contains the referenced element. User agents may re-use the same stylesheet objects for any shadow trees that reference that same external document.
So it's the browsers and SVG renderers I tried that are not conforming to the standard.
I'm still looking for a way to emulate this behavior on existing SVG user agents.
Your styles will be applied, provided your svg asset code is inlined
<svg style="display:none" class="svg-asset" width="100" height="100" version="1.1" xmlns="http://www.w3.org/2000/svg">
<style>
#inline-ball { stroke:#ff0000; stroke-width:10; }
</style>
<circle id="inline-ball" cx="50" cy="50" r="45" />
</svg>
<svg width="100" height="100" version="1.1" xmlns="http://www.w3.org/2000/svg">
<use xlink:href="#inline-ball" />
</svg>
If you prefer not to inline svg code then "fragment identifiers" might be the better embedding approach.
It's basically a sprite concept:
So your image assets(like symbols) need to be positioned with some x or y offset on sprite pane (unlike symbols who could be positioned with overlapping).
You're actually loading a complete svg including embedded css style elements but choose a particular view frame.
See this articel on css.tricks.com
css.tricks.com: How SVG Fragment Identifiers Work
Your svg would be something like this
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 32 96" >
<g id="icon01">
<path d="M20.6,23.3L14,16.7V7.9h4v7.2l5.4,5.4L20.6,23.3z M16-0.1c-8.8,0-16,7.2-16,16s7.2,16,16,16s16-7.2,16-16S24.8-0.1,16-0.1z M16,27.9c-6.6,0-12-5.4-12-12s5.4-12,12-12s12,5.4,12,12S22.6,27.9,16,27.9z"/>
</g>
<g id="icon02">
<path d="M32,43.2c0,2.7-1.2,5.1-3,6.8l0,0l-10,10c-1,1-2,2-3,2s-2-1-3-2l-10-10c-1.9-1.7-3-4.1-3-6.8c0-5.1,4.1-9.2,9.2-9.2c2.7,0,5.1,1.2,6.8,3c1.7-1.9,4.1-3,6.8-3C27.9,33.9,32,38.1,32,43.2z"/>
</g>
<view id="icon-clock-view" viewBox="0 0 32 32" />
<view id="icon-heart-view" viewBox="0 32 32 32" />
</svg>
For using the fragment identifiers we need to add <view> elements with corresponding sprite area coordinates (defined in viewBox attribute).
Unlike symbol definitions we don't nest the actual path data in view elements.
Embedding in html works by adding the target ID to our src url.
<img class="svg-fragment" src="fragment-ready-1.svg#icon-heart-view">
However, inlining svg graphics in your html, still offers the best styling controls.
(e.g styling elements in your websites css file)
Maybe we'll see additional support for styling remotely embedded svg assets in the future ... Until then we still have to cope with some browser quirks.

How can you use a symbol from SVG defs.svg as background image in CSS?

I'm trying to use a symbol from my defs.svg as a background image in CSS, as opposed to a direct path to an individual SVG file.
So instead of:
background: url(spoon.svg);
I want to do something like this:
background: url(defs.svg#spoon);
With #spoon being a symbol in defs.svg with id="spoon". Unfortunately, this isn't working for me. Has anyone come across a solution that doesn't involve custom JS/etc?
You'd need to define view and use tags inside your defs.svg so CSS would know where to look and what to show.
So, for example, say you have inside your SVG a symbol defined as this:
<symbol id="poop" viewBox="0 0 100 100">
<!-- Your shapes here -->
</symbol>
And before closing the svg tag, you must add the view and use defining tags:
<view id="poop-view" viewBox="0 0 100 100" /><!-- This ID used here is what you'll use in your CSS! -->
<use xlink:href="poop" width="100" height="100" x="0" y="0"></use>
Note that at this point, you can open your raw SVG file in a browser and it will show your drawing - before it showed blank!
And now you can set your SVG symbol in your CSS:
div{background-image:url("defs.svg#poop-view")} /* Remember, it's the ID used on your <view> def! */
Also, be sure your SVG includes a xmlns:xlink namespace on the opening tag, or it won't be supposed to work.
Disclaimer: I'm trying to use this setup at work hosting the SVG file on a server on my university, but for some reason this doesn't work (even SVG files won't show if <?xml>and <!DOCTYPE> tags are missing on the SVG), so be sure to check the sanity of your SVG file.
Find more about this on Jennifer Hiller's codepen blog.

Referencing SVG with <img> vs <image>

I noticed there are two ways to reference SVG images. You can either use the standard <img> tag
<img src="picture.svg" alt="SVG Image"/>
or you can use <image> tag
<svg>
<image xlink:href="picture.svg" x="0" y="0" height="50px" width="50px"/>
</svg>
To me, it seems better to simply use the <img> tag because you get the alt attribute which makes it more search friendly and you also can apply styles via CSS. I was having trouble applying styles because the SVG <image> requires attributes.
I was wondering if there was a significant reason why you would use the SVG <image> tag over the standard <img>?
The <svg> element is used for putting inline SVG in your document. So in this case, if you want to avoid having to load an external file, you can put the contents of picture.svg directly between the <svg> and </svg> tags.
If that's not the intended purpose, and you just want to show an image that happens to be in SVG format, there's no real reason to put in inside an SVG block; just use <img>.

Resizing an SVG to specific dimensions

I am trying to resize an svg to the exact size which I want it (32x32).
Look at the example at http://jsfiddle.net/Uy94k/6/
This fiddle is a short outtake of a larger .svg file which I include in my html file and refeer to which image I want using:
<svg class="small" viewBox="0 0 512 512" preserveAspectRatio="none">
<g filter="">
<use xlink:href="#login"></use>
</g>
</svg>
(Any easier way to do this by the way?).
As you can see, I've tried using preserveAspectRatio, but without luck. I've also tried different styling techniques (ie. sizing in span tags outside the svn, styling in the svn tags, fiddling with height both in and where I call it by id.).
If you use a developer tool to look at the height/width of the images in the fiddle, you will see that it is 26x20.. But why is that?
Tweeking the viewBox values (guessing the value of viewBox="120 70 340 340" in this case) kinda did the trick. But it is error prone, not nice, and tedious to tweek the parameters.. Look at the example at http://jsfiddle.net/veZSX/1/ for a tweeked vs untweeked version.
There must be a better way?

How can I prepare an Inkscape SVG file for responsive web design?

I've been doing a tutorial on Treehouse on responsive web design. At this point in the tutorial we are asked to convert an image to an svg so it can scale fully responsively.
Rather than use Adobe Illustrator, which I don't own, I used the freeware Inkscape. Once the image is converted we are asked to open the image in a text editor and remove the height and width requirements from the svg declaration and add the object selector to our max width rule to our style css:
img, object {
max-width: 100%;
}
However, after removing height and width the image is not responsive but instead oddly clipped like so:
Does anyone know what error I have made? Or what I should have removed?
Sorry if the question has been asked before, I can't find it.
edit1, the code:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg2985"
version="1.1"
inkscape:version="0.48.4 r9939"
width="319"
height="177"
sodipodi:docname="logo.gif">
<metadata
id="metadata2991">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs2989" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="640"
inkscape:window-height="480"
id="namedview2987"
showgrid="false"
inkscape:zoom="0.94984326"
inkscape:cx="159.5"
inkscape:cy="88.5"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg2985" />
<image
width="319"
height="177"
xlink:href="
It is the "height" and "width" in the first SVG tag that I have removed.
Inkscape now provides an option to enable viewbox if you save the file as "optimized svg".
Very handy!
The fact that you have just put a raster image in your SVG isn't the actual reason for what you are seeing.
All it means is that when the scaling of the SVG works properly (see below), you won't see the benefits of using vector artwork. When you scale up vector artwork, you don't get the "jaggies" (blockiness) that you get when scaling up bitmaps. If your SVG just contains a bitmap, it is pretty much the same as just using the bitmap.
The actual problem here is that Inkscape doesn't include a viewBox attribute in the SVGs it saves.
When you remove the "width" and "height" attributes, they default to "100%". Which tells the browser to scale the SVG to fit the parent container. Unfortunately for this scaling to work, the browser needs to know what the dimensions of the SVG content are. That is what the viewBox attribute is for.
Illustrator adds the viewBox attribute, Inkscape does not.
To see what I mean, add the following to your <svg> tag after removing width and height:
viewBox="0 0 319 177"
You should find that your image is no longer clipped, and will resize when the page is resized.
As you can read it here ( and for completing qed's answer):
Select the object(s) to export
Open the document properties window ( Ctrl+Shift+D)
Select "Resize page to drawing or selection"
File > Save As Copy...
Select Optimized SVG as the format
You've done something wrong if you're "converting" raster to vector graphics. Not having used Inkscape, I can't say, but at least according to Wikipedia it's not capable of performing conversions.
You haven't converted anything, your image is in Graphics Interchange Format!
To see what a "real" SVG file looks like, open up the example from the wiki page.

Resources