SVG sprites: per-instance preserveAspectRatio - css

Is there any way to set the value of preserveAspectRatio for SVG sprites on a per-instance basis using CSS, HTML, or some other method (besides JavaScript)?
For example (none of these appear to work):
<!-- inline html on <svg> -->
<svg preserveAspectRatio="xMinYMin">
<use xlink:href="/svg/icon.svg">
</svg>
.
<!-- inline html on <use> -->
<svg>
<use xlink:href="/svg/icon.svg" preserveAspectRatio="xMinYMin">
</svg>
.
<!-- inline css nested in <svg> -->
<svg>
<style>svg { preserveAspectRatio: xMinYMin; }</style>
<use xlink:href="/svg/icon.svg">
</svg>
.
<!-- inline css nested in <use> -->
<svg>
<use xlink:href="/svg/icon.svg">
<style>svg { preserveAspectRatio: xMinYMin; }</style>
</use>
</svg>
.
<!-- head/external css -->
<style>
.icon,
.icon svg {
preserveAspectRatio: xMinYMin;
}
</style>
<svg class="icon">
<use xlink:href="/svg/icon.svg">
</svg>

In SVG 1.1 you can only use <image> elements to refer to complete files. SVG 2 relaxes this so that <use> elements can point to complete files but I'm not sure any UAs have implemented this.
For image elements you'd do this...
<svg>
<image width="100" height="100" xlink:href="/svg/icon.svg#svgView(preserveAspectRatio(none slice))">
</svg>
In SVG 1.1 width and height are mandatory for images. The svgView syntax is documented here

Related

Cannot Change SVG <use> icon size when linked to <symbol>

I'm trying to use an SVG symbol in my mark-up, but I can't get the CSS to increase the size of the symbol being rendered inside a element?
I have a twitter logo defined in a set of tags, and then I'm referencing this with an xlink:href inside use tags. The icon is showing, but when I add CSS to the #box1 div holding the element the symbol isn't increasing or decreasing in size and seems to only rendering at the viewBox size.
Also, the SVG element itself when I hover it with the dev tools is rendering at 300 x 150px - but there is nothing on in the code with these measurements.
I'm really confused — any help would be awesome.
#box1 {
height: 10rem;
width: 10rem;
}
<defs style="display: none;">
<svg id="twitter" viewBox="0 0 19.19 15.95">
<symbol id="twitter-symbol"><title>twitter</title>
<path id="twitter-path" d="M19.19,1.92a8.76,8.76,0,0,1-2.28.64A3.9,3.9,0,0,0,18.63.32a6.87,6.87,0,0,1-2.52,1A3.87,3.87,0,0,0,13.23,0,4,4,0,0,0,9.32,4,3.41,3.41,0,0,0,9.44,5,11,11,0,0,1,1.32.72a4.29,4.29,0,0,0-.52,2A4,4,0,0,0,2.56,6.12,3.61,3.61,0,0,1,.76,5.6v0a4,4,0,0,0,3.16,4,4.35,4.35,0,0,1-1,.16,4.9,4.9,0,0,1-.76-.08,4,4,0,0,0,3.68,2.8A7.79,7.79,0,0,1,.92,14.19a6.78,6.78,0,0,1-.92,0A10.83,10.83,0,0,0,6,16c7.24,0,11.19-6.16,11.19-11.47V4a6.83,6.83,0,0,0,2-2" fill="#000">
</path>
</symbol>
</svg>
</defs>
<div id="box1">
<svg>
<use xlink:href="#twitter-symbol"/>
</svg>
</div>
The <defs>is an svg element. It always goes inside the svg. I've made a few changes and now it works. Please run the code and take a look at what I've done.
#box1 {
height: 10rem;
width: 10rem;
}
#twitter{display:none;}
<svg id="twitter">
<defs>
<symbol id="twitter-symbol"><title>twitter</title>
<path id="twitter-path" d="M19.19,1.92a8.76,8.76,0,0,1-2.28.64A3.9,3.9,0,0,0,18.63.32a6.87,6.87,0,0,1-2.52,1A3.87,3.87,0,0,0,13.23,0,4,4,0,0,0,9.32,4,3.41,3.41,0,0,0,9.44,5,11,11,0,0,1,1.32.72a4.29,4.29,0,0,0-.52,2A4,4,0,0,0,2.56,6.12,3.61,3.61,0,0,1,.76,5.6v0a4,4,0,0,0,3.16,4,4.35,4.35,0,0,1-1,.16,4.9,4.9,0,0,1-.76-.08,4,4,0,0,0,3.68,2.8A7.79,7.79,0,0,1,.92,14.19a6.78,6.78,0,0,1-.92,0A10.83,10.83,0,0,0,6,16c7.24,0,11.19-6.16,11.19-11.47V4a6.83,6.83,0,0,0,2-2" fill="#000">
</path>
</symbol>
</defs>
</svg>
<div id="box1">
<svg viewBox="0 0 19.19 15.95" width="24">
<use xlink:href="#twitter-symbol"/>
</svg>
</div>
I hope it helps.
You're using inline SVG code within your HTML, so I believe that SVG path needs a viewbox defined within it. For example, if you add viewBox="0 0 60 55" within your HTML SVG tag, you'll notice that the size will start to adjust. So edit this part of your HTML
<svg viewBox="0 0 60 55">
<use xlink:href="#twitter-symbol"/>
</svg>
To expand on your note where you found the size listed as 300x150, this is the default standard size that applies to HTML inline SVG code (per HTML5 specs). This differs sometimes depending on the browser.
Keep in mind, there a are a few different methods you can use when handling SVGs. Check out the guide below where they give a nice run down on SVG and how to manipulate it's size. You might find an alternative way that you would prefer to use.
https://css-tricks.com/scale-svg/

Viewbox placement in referencing SVG symbols and CSS dimensions

I edited my initial cry of despair into something more to the technical point, in order to turn it into a Q&A.
I'm using SVG symbols that I reference in the document with use elements. I'm styling these with CSS. I don't want to set both height and width in the CSS, I want to set only one of them with the other one scaling accordingly.
I do set a viewBox attribute on the symbol. But the graphic does not scale correctly.
<!DOCTYPE html>
<html>
<head>
<title>SVG Symbols</title>
<style>
body { margin: 20px; }
.svg-large { width: 500px; fill: yellow;}
</style>
</head>
<body>
<svg style="display:none;">
<symbol id="scary-smiley" viewBox="0 0 20 20">
<circle cx="10" cy="10" r="9.5" stroke-width="1"
stroke="black" />
<circle cx="6" cy="7" r="1.5" fill="black"/>
<circle cx="14" cy="7" r="1.5" fill="black"/>
<image xlink:href="https://upload.wikimedia.org/wikipedia/commons/thumb/1/14/Teeth_by_David_Shankbone.jpg/320px-Teeth_by_David_Shankbone.jpg"
width="10" height="5.2" x="5" y="11"/>
</symbol>
</svg>
<svg class="svg-large">
<use xlink:href="#scary-smiley"/>
</svg>
</body>
</html>
The code below has been tested in current Firefox, Chrome and a Webkit-based browser named Midori.
For some reason, defining the viewBox on the symbol element does not have the full desired effect in Firefox and Chrome. It does have some effect, though, as it makes the element scaleable. So, if you want set both width and height in CSS, you can do that.
If the viewBox element is specified only on the symbol and you set only one of width or height, then in Firefox and Chrome the other dimension is set according the default object size in HTML 5 whis is 300x150 px. So, in the example in the question, you get a 500x150 px element and the graphic is scaled to fit that rectangle.
If you want to define only one width or height with the other one scaling accordingly, then defining viewBox on the referencing SVG element works:
<!DOCTYPE html>
<html>
<head>
<title>SVG Symbols</title>
<style>
body { margin: 20px; }
.svg-large { width: 500px; fill: yellow;}
</style>
</head>
<body xmlns:xlink="http://www.w3.org/1999/xlink">
<svg style="display:none;">
<symbol id="scary-smiley">
<circle cx="10" cy="10" r="9.5" stroke-width="1"
stroke="black" />
<circle cx="6" cy="7" r="1.5" fill="black"/>
<circle cx="14" cy="7" r="1.5" fill="black"/>
<image xlink:href="https://upload.wikimedia.org/wikipedia/commons/thumb/1/14/Teeth_by_David_Shankbone.jpg/320px-Teeth_by_David_Shankbone.jpg"
width="10" height="5.2" x="5" y="11"/>
</symbol>
</svg>
<svg class="svg-large" viewBox="0 0 20 20">
<use xlink:href="#scary-smiley"/>
</svg>
</body>
</html>
Firefox' and Chrome's behaviour is standard compliant, according to the SVG 2 specification, according to which the <svg><use .../></svg> clause establishes a new SVG viewport.

Can't control SVG icon fill color with CSS styles

I have read all post in here about styling my svg fill color with CSS but without luck.
What I want is to able to make an icon with a link. My external svg file is grey, but I would like to make it red with css and change color to yellow when hovering.
I think I am targeting the SVG wrong. Please help. My test is here:
testpage
<%#LANGUAGE="VBSCRIPT" CODEPAGE="1252"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Test</title>
</head>
<style type="text/css">
<!--
.svgicon {
fill: red;
}
.svgicon:hover {
fill: yellow;
}
-->
</style>
<body>
<table width="100%" border="0" class="tabelform">
<tr>
<td width="100%"><object type="image/svg+xml" data="S/Images/new.svg" height="18" width="18"></object>test icon</td>
</tr>
</table>
</body>
</html>
Answer a little overdue, but worth having for reference for others.
Basically, the only type of SVG usage which can be used in conjunction with CSS is the inline usage.
This means you would literally put your SVG markup directly into the HTML source as follows:
<div class="my-svg">
<svg xmlns="http://www.w3.org/2000/svg" id="SVG-dropdown-icon" viewBox="0 0 15 11">
<title>
Expand
</title>
<path d="M1.758 1L7.5 6.582 13.242 1 15 2.709 7.5 10 0 2.709z"/>
</svg>
</div>
NOTE: This SVG has been optimised using SVGO and then manually edited to include and ID
You can now control the SVG using CSS like so:
.my-svg {
fill: pink;
}
.my-svg:hover {
fill: red;
}
currentColor
You can also use the currentColor keyword in the SVG to apply a colour to certain elements of it, for example:
<div class="my-svg">
<svg id="SVG-active-icon" viewBox="0 0 25 25" xmlns="http://www.w3.org/2000/svg">
<title>
Current Event
</title>
<g fill="none" fill-rule="evenodd">
<circle class="activeEventPulse" stroke="currentColor" fill="#EBEBED" cx="12.5" cy="12.5" r="11.5"/>
<ellipse fill="currentColor" cx="12.5" cy="12.5" rx="4.5" ry="4.5"/>
</g>
</svg>
</div>
.my-svg {
color: red;
}
JS Fiddle
This can be handy if you need to use the same SVG across different websites / themes, such as dark and light, for easily switching SVG colours with CSS.
Caching / performance consideration: SVG cloning
You should also keep in mind, it's not a good idea to use inline SVG for repetitive images, such as icons, because they can not be cached (the SVG code will be repeated throughout your HTML, increasing the ultimate file size).
Instead, one approach I like to use is to create an SVG index at the top of my page, which contains all the SVGs I want to use on the page, for example:
<svg xmlns="http://www.w3.org/2000/svg" class="svg-index">
<svg xmlns="http://www.w3.org/2000/svg" id="SVG-dropdown-icon" viewBox="0 0 15 11">
<title>
Expand
</title>
<path d="M1.758 1L7.5 6.582 13.242 1 15 2.709 7.5 10 0 2.709z"/>
</svg>
<svg id="SVG-active-icon" viewBox="0 0 25 25" xmlns="http://www.w3.org/2000/svg">
<title>
Current Event
</title>
<g fill="none" fill-rule="evenodd">
<circle class="activeEventPulse" stroke="currentColor" fill="#EBEBED" cx="12.5" cy="12.5" r="11.5"/>
<ellipse fill="currentColor" cx="12.5" cy="12.5" rx="4.5" ry="4.5"/>
</g>
</svg>
</svg>
Make sure you set the SVG index to display: none so it doesn't show up on the page.
You can now reuse these SVGs repetitively throughout the page using the xlink:href attribute as follows:
<svg class="dropDown">
<use xlink:href="#SVG-dropdown-icon" />
</svg>
<svg class="active">
<use xlink:href="#SVG-active-icon" />
</svg>
<svg class="active">
<use xlink:href="#SVG-active-icon" />
</svg>
<svg class="dropDown">
<use xlink:href="#SVG-dropdown-icon" />
</svg>
JS Fiddle
This is called cloning, and allows you to take advantage of cacheable SVGs which can be controlled with CSS!
Hope this helps!
try to use inline svg instead of external svg source then you can control

Add css to svg with inkscape

I use Inkscape for creating svg images and want to know how to use not embedded css rules.
For example
draw rectangle
in XML-editor add class attribute as
class="rect1"
to svg:rect object
How to add css like
.rect1 {
fill:#ffef00;
}
Here's an example of an SVG in an HTML page that you can style with CSS:
HTML page
<div id="mySvg">
<svg>
<use xlink:href="images/logo.svg#shape" />
</svg>
</div>
The SVG (located at images/logo.svg)
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<g id="shape">
<rect x="50" y="50" width="50" height="50" />
<circle cx="50" cy="50" r="50" />
</g>
</defs>
</svg>
The CSS
svg {
fill: currentColor;
}
#mySvg {
color: green;
}
See working example: plunker
Notes
If you use Inkscape to create your SVG, you'll probably have to do some hand-editing of the SVG to make it styleable with CSS.
Make sure the SVG code doesn't have any fill attributes in it (fill should be in the CSS). When making an SVG with Inkscape, it often has a fill:none or something. You'll have to manually remove those.
When using Inkscape, save files as "Optimized SVG" as described here.

Style part of svg when using it via use

Is it possible style an svg icon embedded using the svg-use syntax only within a certain item?
I can easily style the icon in general, but I would like to style a part of an svg icon when the icon is used within the nav-item.
This is what I tried without any success.
// css
.nav-item .part1{
opacity: 0.5;
}
When using the svg like this:
<svg id="svg_sprite" style="display: none;">
<defs>
<g id="icon">
<polygon points="476.5,379.778 401.167,..."></polygon>
<polygon class="page1" points="221,379.768 85.334,..."></polygon>
</g>
</defs>
</svg>
<li class="nav-item">
<svg viewBox="0 0 512 512" class="icon">
<use xlink:href="#icon"></use>
</svg>
</li>
The answer is no. You cannot style an element based on whether it has been referenced by a <use> or not. The SVG spec specifically says this. The reason is that the content referenced by the <use> is only a "conceptual clone" and is not actually part of the DOM.
http://www.w3.org/TR/SVG11/struct.html#UseElement

Resources