Where to put <style> inside SVG? - svg

Sorry if that might come an opinion-based, but I hope there's a right answer..
Where an inline CSS style should be placed inside an SVG document? In the
example I provide below I have defined two styles and a circle that uses them.
The first style is defined inside defs tag and the second styles is defined right inside the svg tag.
Both styles are successfully displayed on the circle (at least in Chrome they do, didn't check other browsers though).
My question is which way is more standard?
I think keeping styles in defs keeps the whole SVG more tidy. However, one can claim that I should not use defs tag since no one references the style with <use>
Thanks!
<svg height="100" width="100">
<defs id="someDefs">
<style id="style1">
.blue-fill {
fill : blue;
}
</style>
</defs>
<style id="style2">
.red-stroke {
stroke : red;
stroke-width : 12
}
</style>
<circle cx="50" cy="50" r="40" class="blue-fill red-stroke" />
</svg>

It doesn't matter. Neither approach is "more standard". <style> elements are not renderable anyway, so there is no real need to put them in the <defs> section
As commented by Paul LeBeau.
After reading this article about style on MDN, that shows an example of a style simply under the SVG root, I am more convinced it is correct to put <style> there rather than under <defs>.
Also, since <defs> tag is indeed for reusable graphical elements that should be rendered, and <style> is not a renderable element, there's no point keeping it there.

Graphical elements defined in <defs> are not rendered directly and will be rendered only with use. Hence it is always a good practice to use <defs> if the graphical object is defined for later use. It also increases the readability of the code.
More Information

Related

Embedded SVG into Inkscape

I have a SVG file (an exported Gliffy diagram) that I want to open and edit in Inkscape. When viewing the code of the file using the developer options of Chrome, it looks like:
<svg xmlns="...>
<g transform="...>
<image xlink:href="data:image/svg+xml,%0A%20...></image>
</g>
... (about 20 more <g>...</g> tags)
</svg>
When decoding the part starting with %0A%20..., it translates to something like
data:image/svg xml,
<svg xmlns="http://www.w3.org/2000/svg" height="50000" width="50000">
<style>
.gliffy-rte-text {
...
The issue is, that in Inkscape those parts will be replaced by a placeholder telling me "Linked image not found" and as speculated here, Inkscape most likely is not able to read the CSS styling correctly or probably at all.
I would very much appreciate any thoughts or ideas on how to convert the file such that it can be edited and displayed correctly in Inkscape.
You might convert all styling to element attributes using SVGOMG:
replace your embedded <image> element by the decoded data url content. Your parent svg should look something like this:
<!-- parent svg -->
<svg xmlns="http://www.w3.org/2000/svg" >
<!-- embedded svg decoded data url -->
<svg xmlns="http://www.w3.org/2000/svg" height="50000" width="50000">
<style>
.gliffy-rte-text {
}
</style>
</svg>
</svg>
Use SVGOMG "inline styles" and "style to attribute"parameter:
You should disable all other optimizing parameter, since they might strip to many other attributes.
Expected before result
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
<style>
circle{
fill:none;
stroke: orange;
stroke-width:10;
}
</style>
<circle cx="128" cy="128" r="100"/>
</svg>
After
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
<circle cx="128" cy="128" r="100" fill="none" stroke="orange" stroke-width="10"/>
</svg>
Open the wrapper file in a browser. Right-click on the area containing the embedded SVG, and choose "Save (image) as...". If the wrapper contains multiple <image> tags, you will have to save them to separate files, but at least they will be in a form Inkscape can handle.
If you want to get them all together in one SVG file again, you will have to re-import them via the Inkscape import function. Take care to select 'Include as editable object', or you will end up right where you started:
The speculations above about CSS are unsubstantiated, btw. Inkscape will convert the content of a <style> element into inline style attributes, but otherwise handle them correctly. What happened is stated quite clearly in the above screenshot: data URLs embeded via an <image> tag will not be editable in Inkscape.

Making screen-readers read out <text> items in SVG graphics?

I've searched all over the place and not have any success with this.
I'm making SVGs like the following one in order to make them scalable, and also help people who are dyslexic so they can highlight the text and use plugins like Read Out Loud:
https://www.ole.bris.ac.uk/bbcswebdav/institution/TEL/TEL%20guides/Published%20TEL%20guides/Replay/record-now-instructions-web.svg
But I've not been able to get my copy of NVDA to read out the tab-indexed fields as I tab through them. I've tried fields and aria-label on various things...
Is there something simple I can change so NVDA (and similar screen readers) will read out the text as I tab through (NVDA does this on HTML pages).
Or should I just put the full description of all the text in my description at the top?
I noticed you have role="img" in your svg root. That's borking everything, since it tells the accessibility API that it is just a single element, whose accessible name is always aria-labelledby="svgTitle svgDesc"
Try changing that to role="graphics-document" (or perhaps role="application" if you want fancier interactions) and I think you'll have a whole lot more luck.
The other option is to remove the role attribute from the <svg> element. It sounds counterintuative, but it should make any <text> elements accessible.
For an example, see tip 5 in this SitePoint article, which has great background and other helpful tips on making SVG more accessible in different use cases:
Tips for Creating Accessible SVG
From the above article:
<svg version="1.1" width="300" height="200" aria-labelledby="title desc">
<title id="title">Green rectangle</title>
<desc id="desc">A light green rectangle with rounded corners and a dark green border.</desc>
<rect width="75" height="50" rx="20" ry="20" fill="#90ee90" stroke="#228b22" stroke-fill="1" />
<text x="35" y="30" font-size="1em" text-anchor="middle" fill="#000000">Website</text>
</svg>

Display of SVG on Leaflet map

I have a moderately large SVG to be displayed as an overlay on a Leaflet map - it's basically a selection of roads from a road network. The leaflet map is instantiated with:
testMap = L.map('mapdiv', { renderer: L.svg({ padding: 100 }) })
.setView([33.085, -96.815], 11);
and the SVG layer is created with:
var imgUrl = url, imgBnds;
L.imageOverlay(imgUrl, imgBnds, {opacity:0.3}).addTo(testMap);
This all displays nicely when zoomed out, but when zooming in, the SVG gets tiled, and only the top-left tile is displayed even though this is not the area being shown in the map.
The SVG has the following:
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" xml:space="preserve"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" x="0" y="0" width="1920" height="767"
clip-path="url(#MapClipRectangle)" style="overflow:hidden;text-rendering:optimizeLegibility" xmlns="http://www.w3.org/2000/svg">
</desc>
<defs>
<clipPath clipPathUnits="userSpaceOnUse" id="MapClipRectangle">
<rect x="0" y="0" width="1920" height="767" />
</clipPath>
<symbol id="1" style="fill:none">
<path d="M985.96 476.76 l-0.26 0.06" />
<!-- ... Many Symbols and Paths, plus some Polygons, Text, Line_artwork, Map_decoration and a Map_frame... -->
And it ends up looking like this (example actually shows the top-left tile, but if I zoom in to the right, you don't actually see anything from the overlay SVG):
How do you stop/control this behaviour?
Sample SVG for which this behaviour occurs
I have not investigated this question in any depth, but in the interest of having some answer at all that might help:
It seems unusual to me that you want to use an svg for geospatial data like a road network.
If someone runs into a similar problem in the future, I would recommend, rather than trying to fix the svg rendering, convert the data to geojson which is more of a standard option for this sort of data display need and then style as needed using the options in leaflet.
To OP, did you ever find a solution?
As a note, it is not clear to me which part of the images posted are svg's vs which parts are basemap or other layers.

How can I add multiple of lines text (a paragraph) to an svg?

I want to add multiple lines of text to an svg, which would be contained within the svg (does not overflow). How can I do that?
I knew that the text tag is used in svg, but I discovered that it's single lined. Then, when I give it textLength (so that it would contained in specific svg), its words overlap with each other. How can I put multiple lines of text which would adjust in svg tag? The code I tried is below:
<svg width="200" height="60" style="border: 1px solid black;">
<text x="10" y="30" textLength="180" style="font-size: 30px;">The paragraph here</text>
</svg>
It doesn't work. SVG has no mechanism for breaking lines.
That said, you would be able to encapsulate a html <p> tag as a foreignObject:
<svg xmlns="http://www.w3.org/2000/svg"
width="21cm" height="29.7cm" style="border:1px solid black;">
<foreignObject x="6.4cm" y="3.6cm" width="10cm" height="10cm">
<p xmlns="http://www.w3.org/1999/xhtml"
style="font-size:48px;">The paragraph here</p>
</foreignObject>
</svg>
Please note that the namespace declarations must be given, and you need to write valid XHML for this to work.
In addition, foreignObject is part of the SVG context, so a width and height need to be set, otherwise it will have no inherent size.

Change Part of Symbol Color SVG

I have an SVG symbol, basically three paths with an all black stroke. This symbol is used heavily across my SVG document using the use tag.
Sometimes i just want to change only one stroke of the instances of the symbol, like color variations, How can i achieve this using SVG+CSS, knowing that I used 'use' to create the symbol instances.
This actually is a very neat trick http://codepen.io/FWeinb/blog/quick-tip-svg-use-style-two-colors, Fabrice Weinberg here is using fill="currentColor" on the symbol so he can change it later using css.
<svg style="display:none;">
<symbol id="test">
<rect x="10" y="10" width="100" height="100" />
<rect x="100" y="10" width="100" height="100" fill="currentColor" />
</symbol>
</svg>
<svg class="icon icon--BlueBlack"><use xlink:href="#test" /></svg>
<svg class="icon icon--BlueGreen"><use xlink:href="#test" /></svg>
and
.icon--BlueBlack{
fill:blue;
}
.icon--BlueGreen{
fill:blue;
color:green;
}
According to the SVG 1.1 spec on the use element:
The effect of a ‘use’ element is as if the contents of the referenced
element were deeply cloned into a separate non-exposed DOM tree […]
The SVG DOM does not show the referenced element's contents as
children of ‘use’ element.
That implies that the referenced elements children are not accessible by traversing your DOM tree. This also holds true for access via css selectors as the spec goes on:
CSS2 selectors cannot be applied to the (conceptually) cloned DOM tree
because its contents are not part of the formal document structure.
It is possible. You can't style the dereferenced symbol contents directly with CSS. But you can style the parent <use> element and have that colour inherit into the symbol. See the answers to the following question for examples.
How to style one particular SVG path in CSS?

Resources