Velocity Conf, NYC, October 14th, 2015
Presentation Attributes will override inherited styles specified on a parent element.
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="300px" height="300px" viewBox="0 0 300 300"> <polygon fill = "#FF931E" stroke = "#ED1C24" stroke-width = "5" points = "279.1,160.8 195.2,193.3 174.4,280.8 117.6,211.1 27.9,218.3 76.7,142.7 42.1,59.6 129.1,82.7 197.4,24.1 202.3,114 "/> </svg>
Styles lower in the diagram override those above them
<style> circle {fill: orange;} </style> <svg version="1.1" viewBox="0 0 400 400"> <g fill="yellow"> <circle cx="100" cy="100" r="100" fill="blue" /> <!-- ... --> </g> </svg>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" style="display: none;"> <symbol id="icon-twitter" viewBox="0 0 35 35"> <!-- Twitter icon markup --> </symbol> <symbol id="icon-github" viewBox="0 0 35 35"> <!-- Github icon markup --> </symbol> <!-- more icons here... --> </svg>
<svg class="icon-twitter"> <use xlink:href="#icon-twitter"></use> </svg>
<svg class="icon-twitter"> <use xlink:href="icons.svg#icon-twitter"></use> </svg>
Does not work in IE. Works in Edge.
<style> use {fill: orange;} </style> <svg version="1.1" viewBox="0 0 400 400"> <symbol id="myCirc" viewBox="0 0 32 32">
<circle cx="100" cy="100" r="100" fill="blue"/>
</symbol>
<use xlink:href="#myCirc"...></use>
</svg>
This is common in reusable SVG icons in icon sprites.
circle { fill: inherit; stroke: inherit; }
Force the browser into inheriting the styles by taking advantage of the cascade and the CSS `inherit` keyword
P.S. Make sure you set this rule _before_ any new style declarations in the CSS.
svg * { all: inherit; }
Extreme Measure
Note that this will:
1. reset all the SVG attributes that can be set in CSS except transforms for now (which is good considering the use case, cz u would want to change styles but not transformations + the latter are chained into a matrix!)
2. reset _all_ of those properties — so if u don't specify an alternate value, it will default to browser defaults.
3. This is great for overriding and "bare-boning" SVG elements to allow you to control them completely from the CSS (use case: an SVG whose innards you can't control)
Further Styling Control w/ CSS Variables
<svg class="bird">
<use xlink:href="#bulbul"></use>
</svg>
use {
color: gray;
fill: currentColor; /* this will be the base fill color inherited by all elements inside <use> */
/* define variables here */
--secondaryColor: yellow;
--tertiaryColor: black;
}
Continued
HTML
CSS
Further Styling Control w/ CSS Variables
<symbol id="bulbul" viewBox="0 0 300 200">
<path id="body" d="…" />
<path id="tail" style="fill: ..." fill="var(--tertiaryColor)" d="…" />
<path id="head" style="fill: ..." fill="var(--tertiaryColor)" d="…" />
<path id="vent" style="fill: ..." fill="var(--secondaryColor)" d="…" />
</symbol>
SVG
Links (<a>) inside an SVG embedded as an <object> will open inside the boundaries of that <object>, not in the main page.
(—predictably so, considering that <object> is similar in functionality to <iframe>.)
<img src="logo.svg" alt="Company Logo" />
.el {background: url(mySVG.svg);}
<object type="image/svg+xml" data="mySVG.svg">
<!--fallback (avoid double downloads!)-->
</object>
<embed type="image/svg+xml" src="mySVG.svg" />
<iframe src="mySVG.svg">
<!--fallback-->
</iframe>
<svg><!--SVG content--></svg>
<object type="image/svg+xml" data="mySVG.svg">
<img src="fallback.png" alt="..." />
</object>
Don't do this:
Do this instead:
<object type="image/svg+xml" data="mySVG.svg">
<div id="fallback"></div>
</object>
#fallback { background-image: url('fallback.png'); /* ... */ }
Learn more about it: http://sarasoueidan.com/blog/svg-picture/
<picture> <source type="image/svg+xml" srcset="path/to/image.svg"> <img src="path/to/fallback.png" alt="..."> </picture>
Better fallback and art direction options.
<a role="link" tabindex="0" xlink:href="..." xlink:title="..." xlink:target="_parent" ...> Visit Page </a>
Specify the target of the link using the xlink:target attribute
Remember to...
Setting `fill: none` on path area will disable pointer events on that area.
pointer-events: visiblePainted;
The given element can be the target element for pointer events when the ‘visibility’ property is set to visible and when the pointer is over a "painted" area. The pointer is over a painted area if it is over the interior (i.e., fill) of the element and the ‘fill’ property has an actual value other than none or it is over the perimeter (i.e., stroke) of the element and the ‘stroke’property is set to a value other than none.
Set the fill to "transparent" instead of "none"
<path ... fill="transparent" ...></path>
Change the value of the `pointer-events` property on the element.
visiblePainted | visibleFill | visibleStroke | visible |
painted | fill | stroke | all | none | inherit
Check out what these values mean in the specification.
Changing the transform origin value halfway through a sequence of animation will cause unsightly jumps of the affected element.
In simple terms, once you scale or rotate an SVG element and then change its transformOrigin, the newtransformOrigin is aligned to where it would have been according to the elements un-transformed state. This forces the element to be re-positioned and then the transforms are applied – leading to some awkward results.
Image credit: GreenSock. (http://greensock.com/svg-tips)
Use JavaScript to gain full control and manually do the math and transformations needed to avoid this.
OR
Use GSAP.
GSAP helps avoid, overcome and word around browser bugs and inconsistencies when animating SVGs.
Cropping the SVG using the viewBox attribute can yield unwanted visible overflow.
LIVE DEMO'ING
Change the aspect ratio of the <svg> (the viewport) to match that of the new viewBox.
Clip the overflow out using clip-path
<svg ... clip-path="url(#clipper") viewBox="vx vy width height">
<defs>
<clipPath id="clipper">
<rect x="vx" y="vy" width="100%" height="100%"></rect>
</clipPath>
</defs>
<!-- other svg content & styles -->
</svg>
This trick can also be used to visualise and troubleshoot viewBox problems.
You might want to reposition and/or scale the viewBox after clipping/cropping it. Do that using the preserveAspectRatio attribute.
Read
Everything you need to know about the SVG viewport, viewBox and preserveAspectRatio:
http://sarasoueidan.com/blog/svg-coordinate-systems
(Includes an interactive demo.)
CSSOM methods produce unexpected values when retrieving an SVG element's bounding box properties.
CSSOM's `getClientRects()` and `getBoundingClientRect()` method(s) can be used to get the top, right, bottom and left offset coordinates of an element and the width and height of the element's bounding rectangle.
...can yield unexpected results.
getBoundingClientRect()
expected result
Use getBBox() instead of the CSSOM Methods
var svgElement = document.getElementById('el'); bbox = svgElement.getBBox(); console.log( bbox.x ) ; console.log( bbox.y ) ; console.log( bbox.width ) ; console.log( bbox.height ) ;
Important Note
[getBBox()] returns the tight bounding box in current user space (i.e., after application of the ‘transform’ attribute, if any) on the geometry of all contained graphics elements, exclusive of stroking, clipping, masking and filter effects).
Extra Tip
Use an element's bounding box properties (bbox.x, bbox.y, bbox.width, bbox.height) to define the viewBox area when cropping an SVG to that element.
viewBox="x y width height"
viewBox="bbox.x bbox.y bbox.width bbox.height"
SVG lacks the concept of relative positioning. i.e. You cannot position elements relative to each other like with HTML.
SVG elements are not governed by a box model.
A Workaround
The inner <svg> gets its properties from the nest’s bounding box properties, and the bird goes INSIDE the <svg> and is positioned relative to it.
Root <svg>